Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0
0002 /* Copyright (c) 2019-2021 Marvell International Ltd. All rights reserved */
0003 
0004 #include <linux/rhashtable.h>
0005 
0006 #include "prestera.h"
0007 #include "prestera_hw.h"
0008 #include "prestera_router_hw.h"
0009 #include "prestera_acl.h"
0010 
0011 /*            +--+
0012  *   +------->|vr|<-+
0013  *   |        +--+  |
0014  *   |              |
0015  * +-+-------+   +--+---+-+
0016  * |rif_entry|   |fib_node|
0017  * +---------+   +--------+
0018  *  Rif is        Fib - is exit point
0019  *  used as
0020  *  entry point
0021  *  for vr in hw
0022  */
0023 
0024 #define PRESTERA_NHGR_UNUSED (0)
0025 #define PRESTERA_NHGR_DROP (0xFFFFFFFF)
0026 
0027 static const struct rhashtable_params __prestera_fib_ht_params = {
0028     .key_offset  = offsetof(struct prestera_fib_node, key),
0029     .head_offset = offsetof(struct prestera_fib_node, ht_node),
0030     .key_len     = sizeof(struct prestera_fib_key),
0031     .automatic_shrinking = true,
0032 };
0033 
0034 int prestera_router_hw_init(struct prestera_switch *sw)
0035 {
0036     int err;
0037 
0038     err = rhashtable_init(&sw->router->fib_ht,
0039                   &__prestera_fib_ht_params);
0040     if (err)
0041         goto err_fib_ht_init;
0042 
0043     INIT_LIST_HEAD(&sw->router->vr_list);
0044     INIT_LIST_HEAD(&sw->router->rif_entry_list);
0045 
0046 err_fib_ht_init:
0047     return 0;
0048 }
0049 
0050 void prestera_router_hw_fini(struct prestera_switch *sw)
0051 {
0052     WARN_ON(!list_empty(&sw->router->vr_list));
0053     WARN_ON(!list_empty(&sw->router->rif_entry_list));
0054     rhashtable_destroy(&sw->router->fib_ht);
0055 }
0056 
0057 static struct prestera_vr *__prestera_vr_find(struct prestera_switch *sw,
0058                           u32 tb_id)
0059 {
0060     struct prestera_vr *vr;
0061 
0062     list_for_each_entry(vr, &sw->router->vr_list, router_node) {
0063         if (vr->tb_id == tb_id)
0064             return vr;
0065     }
0066 
0067     return NULL;
0068 }
0069 
0070 static struct prestera_vr *__prestera_vr_create(struct prestera_switch *sw,
0071                         u32 tb_id,
0072                         struct netlink_ext_ack *extack)
0073 {
0074     struct prestera_vr *vr;
0075     int err;
0076 
0077     vr = kzalloc(sizeof(*vr), GFP_KERNEL);
0078     if (!vr) {
0079         err = -ENOMEM;
0080         goto err_alloc_vr;
0081     }
0082 
0083     vr->tb_id = tb_id;
0084 
0085     err = prestera_hw_vr_create(sw, &vr->hw_vr_id);
0086     if (err)
0087         goto err_hw_create;
0088 
0089     list_add(&vr->router_node, &sw->router->vr_list);
0090 
0091     return vr;
0092 
0093 err_hw_create:
0094     kfree(vr);
0095 err_alloc_vr:
0096     return ERR_PTR(err);
0097 }
0098 
0099 static void __prestera_vr_destroy(struct prestera_switch *sw,
0100                   struct prestera_vr *vr)
0101 {
0102     list_del(&vr->router_node);
0103     prestera_hw_vr_delete(sw, vr->hw_vr_id);
0104     kfree(vr);
0105 }
0106 
0107 static struct prestera_vr *prestera_vr_get(struct prestera_switch *sw, u32 tb_id,
0108                        struct netlink_ext_ack *extack)
0109 {
0110     struct prestera_vr *vr;
0111 
0112     vr = __prestera_vr_find(sw, tb_id);
0113     if (vr) {
0114         refcount_inc(&vr->refcount);
0115     } else {
0116         vr = __prestera_vr_create(sw, tb_id, extack);
0117         if (IS_ERR(vr))
0118             return ERR_CAST(vr);
0119 
0120         refcount_set(&vr->refcount, 1);
0121     }
0122 
0123     return vr;
0124 }
0125 
0126 static void prestera_vr_put(struct prestera_switch *sw, struct prestera_vr *vr)
0127 {
0128     if (refcount_dec_and_test(&vr->refcount))
0129         __prestera_vr_destroy(sw, vr);
0130 }
0131 
0132 /* iface is overhead struct. vr_id also can be removed. */
0133 static int
0134 __prestera_rif_entry_key_copy(const struct prestera_rif_entry_key *in,
0135                   struct prestera_rif_entry_key *out)
0136 {
0137     memset(out, 0, sizeof(*out));
0138 
0139     switch (in->iface.type) {
0140     case PRESTERA_IF_PORT_E:
0141         out->iface.dev_port.hw_dev_num = in->iface.dev_port.hw_dev_num;
0142         out->iface.dev_port.port_num = in->iface.dev_port.port_num;
0143         break;
0144     case PRESTERA_IF_LAG_E:
0145         out->iface.lag_id = in->iface.lag_id;
0146         break;
0147     case PRESTERA_IF_VID_E:
0148         out->iface.vlan_id = in->iface.vlan_id;
0149         break;
0150     default:
0151         WARN(1, "Unsupported iface type");
0152         return -EINVAL;
0153     }
0154 
0155     out->iface.type = in->iface.type;
0156     return 0;
0157 }
0158 
0159 struct prestera_rif_entry *
0160 prestera_rif_entry_find(const struct prestera_switch *sw,
0161             const struct prestera_rif_entry_key *k)
0162 {
0163     struct prestera_rif_entry *rif_entry;
0164     struct prestera_rif_entry_key lk; /* lookup key */
0165 
0166     if (__prestera_rif_entry_key_copy(k, &lk))
0167         return NULL;
0168 
0169     list_for_each_entry(rif_entry, &sw->router->rif_entry_list,
0170                 router_node) {
0171         if (!memcmp(k, &rif_entry->key, sizeof(*k)))
0172             return rif_entry;
0173     }
0174 
0175     return NULL;
0176 }
0177 
0178 void prestera_rif_entry_destroy(struct prestera_switch *sw,
0179                 struct prestera_rif_entry *e)
0180 {
0181     struct prestera_iface iface;
0182 
0183     list_del(&e->router_node);
0184 
0185     memcpy(&iface, &e->key.iface, sizeof(iface));
0186     iface.vr_id = e->vr->hw_vr_id;
0187     prestera_hw_rif_delete(sw, e->hw_id, &iface);
0188 
0189     prestera_vr_put(sw, e->vr);
0190     kfree(e);
0191 }
0192 
0193 struct prestera_rif_entry *
0194 prestera_rif_entry_create(struct prestera_switch *sw,
0195               struct prestera_rif_entry_key *k,
0196               u32 tb_id, const unsigned char *addr)
0197 {
0198     int err;
0199     struct prestera_rif_entry *e;
0200     struct prestera_iface iface;
0201 
0202     e = kzalloc(sizeof(*e), GFP_KERNEL);
0203     if (!e)
0204         goto err_kzalloc;
0205 
0206     if (__prestera_rif_entry_key_copy(k, &e->key))
0207         goto err_key_copy;
0208 
0209     e->vr = prestera_vr_get(sw, tb_id, NULL);
0210     if (IS_ERR(e->vr))
0211         goto err_vr_get;
0212 
0213     memcpy(&e->addr, addr, sizeof(e->addr));
0214 
0215     /* HW */
0216     memcpy(&iface, &e->key.iface, sizeof(iface));
0217     iface.vr_id = e->vr->hw_vr_id;
0218     err = prestera_hw_rif_create(sw, &iface, e->addr, &e->hw_id);
0219     if (err)
0220         goto err_hw_create;
0221 
0222     list_add(&e->router_node, &sw->router->rif_entry_list);
0223 
0224     return e;
0225 
0226 err_hw_create:
0227     prestera_vr_put(sw, e->vr);
0228 err_vr_get:
0229 err_key_copy:
0230     kfree(e);
0231 err_kzalloc:
0232     return NULL;
0233 }
0234 
0235 struct prestera_fib_node *
0236 prestera_fib_node_find(struct prestera_switch *sw, struct prestera_fib_key *key)
0237 {
0238     struct prestera_fib_node *fib_node;
0239 
0240     fib_node = rhashtable_lookup_fast(&sw->router->fib_ht, key,
0241                       __prestera_fib_ht_params);
0242     return fib_node;
0243 }
0244 
0245 static void __prestera_fib_node_destruct(struct prestera_switch *sw,
0246                      struct prestera_fib_node *fib_node)
0247 {
0248     struct prestera_vr *vr;
0249 
0250     vr = fib_node->info.vr;
0251     prestera_hw_lpm_del(sw, vr->hw_vr_id, fib_node->key.addr.u.ipv4,
0252                 fib_node->key.prefix_len);
0253     switch (fib_node->info.type) {
0254     case PRESTERA_FIB_TYPE_TRAP:
0255         break;
0256     case PRESTERA_FIB_TYPE_DROP:
0257         break;
0258     default:
0259           pr_err("Unknown fib_node->info.type = %d",
0260              fib_node->info.type);
0261     }
0262 
0263     prestera_vr_put(sw, vr);
0264 }
0265 
0266 void prestera_fib_node_destroy(struct prestera_switch *sw,
0267                    struct prestera_fib_node *fib_node)
0268 {
0269     __prestera_fib_node_destruct(sw, fib_node);
0270     rhashtable_remove_fast(&sw->router->fib_ht, &fib_node->ht_node,
0271                    __prestera_fib_ht_params);
0272     kfree(fib_node);
0273 }
0274 
0275 struct prestera_fib_node *
0276 prestera_fib_node_create(struct prestera_switch *sw,
0277              struct prestera_fib_key *key,
0278              enum prestera_fib_type fib_type)
0279 {
0280     struct prestera_fib_node *fib_node;
0281     u32 grp_id;
0282     struct prestera_vr *vr;
0283     int err;
0284 
0285     fib_node = kzalloc(sizeof(*fib_node), GFP_KERNEL);
0286     if (!fib_node)
0287         goto err_kzalloc;
0288 
0289     memcpy(&fib_node->key, key, sizeof(*key));
0290     fib_node->info.type = fib_type;
0291 
0292     vr = prestera_vr_get(sw, key->tb_id, NULL);
0293     if (IS_ERR(vr))
0294         goto err_vr_get;
0295 
0296     fib_node->info.vr = vr;
0297 
0298     switch (fib_type) {
0299     case PRESTERA_FIB_TYPE_TRAP:
0300         grp_id = PRESTERA_NHGR_UNUSED;
0301         break;
0302     case PRESTERA_FIB_TYPE_DROP:
0303         grp_id = PRESTERA_NHGR_DROP;
0304         break;
0305     default:
0306         pr_err("Unsupported fib_type %d", fib_type);
0307         goto err_nh_grp_get;
0308     }
0309 
0310     err = prestera_hw_lpm_add(sw, vr->hw_vr_id, key->addr.u.ipv4,
0311                   key->prefix_len, grp_id);
0312     if (err)
0313         goto err_lpm_add;
0314 
0315     err = rhashtable_insert_fast(&sw->router->fib_ht, &fib_node->ht_node,
0316                      __prestera_fib_ht_params);
0317     if (err)
0318         goto err_ht_insert;
0319 
0320     return fib_node;
0321 
0322 err_ht_insert:
0323     prestera_hw_lpm_del(sw, vr->hw_vr_id, key->addr.u.ipv4,
0324                 key->prefix_len);
0325 err_lpm_add:
0326 err_nh_grp_get:
0327     prestera_vr_put(sw, vr);
0328 err_vr_get:
0329     kfree(fib_node);
0330 err_kzalloc:
0331     return NULL;
0332 }