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/kernel.h>
0005 #include <linux/types.h>
0006 #include <linux/inetdevice.h>
0007 #include <net/inet_dscp.h>
0008 #include <net/switchdev.h>
0009 #include <linux/rhashtable.h>
0010 
0011 #include "prestera.h"
0012 #include "prestera_router_hw.h"
0013 
0014 struct prestera_kern_fib_cache_key {
0015     struct prestera_ip_addr addr;
0016     u32 prefix_len;
0017     u32 kern_tb_id; /* tb_id from kernel (not fixed) */
0018 };
0019 
0020 /* Subscribing on neighbours in kernel */
0021 struct prestera_kern_fib_cache {
0022     struct prestera_kern_fib_cache_key key;
0023     struct {
0024         struct prestera_fib_key fib_key;
0025         enum prestera_fib_type fib_type;
0026     } lpm_info; /* hold prepared lpm info */
0027     /* Indicate if route is not overlapped by another table */
0028     struct rhash_head ht_node; /* node of prestera_router */
0029     struct fib_info *fi;
0030     dscp_t kern_dscp;
0031     u8 kern_type;
0032     bool reachable;
0033 };
0034 
0035 static const struct rhashtable_params __prestera_kern_fib_cache_ht_params = {
0036     .key_offset  = offsetof(struct prestera_kern_fib_cache, key),
0037     .head_offset = offsetof(struct prestera_kern_fib_cache, ht_node),
0038     .key_len     = sizeof(struct prestera_kern_fib_cache_key),
0039     .automatic_shrinking = true,
0040 };
0041 
0042 /* This util to be used, to convert kernel rules for default vr in hw_vr */
0043 static u32 prestera_fix_tb_id(u32 tb_id)
0044 {
0045     if (tb_id == RT_TABLE_UNSPEC ||
0046         tb_id == RT_TABLE_LOCAL ||
0047         tb_id == RT_TABLE_DEFAULT)
0048         tb_id = RT_TABLE_MAIN;
0049 
0050     return tb_id;
0051 }
0052 
0053 static void
0054 prestera_util_fen_info2fib_cache_key(struct fib_entry_notifier_info *fen_info,
0055                      struct prestera_kern_fib_cache_key *key)
0056 {
0057     memset(key, 0, sizeof(*key));
0058     key->addr.u.ipv4 = cpu_to_be32(fen_info->dst);
0059     key->prefix_len = fen_info->dst_len;
0060     key->kern_tb_id = fen_info->tb_id;
0061 }
0062 
0063 static struct prestera_kern_fib_cache *
0064 prestera_kern_fib_cache_find(struct prestera_switch *sw,
0065                  struct prestera_kern_fib_cache_key *key)
0066 {
0067     struct prestera_kern_fib_cache *fib_cache;
0068 
0069     fib_cache =
0070      rhashtable_lookup_fast(&sw->router->kern_fib_cache_ht, key,
0071                 __prestera_kern_fib_cache_ht_params);
0072     return fib_cache;
0073 }
0074 
0075 static void
0076 prestera_kern_fib_cache_destroy(struct prestera_switch *sw,
0077                 struct prestera_kern_fib_cache *fib_cache)
0078 {
0079     fib_info_put(fib_cache->fi);
0080     rhashtable_remove_fast(&sw->router->kern_fib_cache_ht,
0081                    &fib_cache->ht_node,
0082                    __prestera_kern_fib_cache_ht_params);
0083     kfree(fib_cache);
0084 }
0085 
0086 /* Operations on fi (offload, etc) must be wrapped in utils.
0087  * This function just create storage.
0088  */
0089 static struct prestera_kern_fib_cache *
0090 prestera_kern_fib_cache_create(struct prestera_switch *sw,
0091                    struct prestera_kern_fib_cache_key *key,
0092                    struct fib_info *fi, dscp_t dscp, u8 type)
0093 {
0094     struct prestera_kern_fib_cache *fib_cache;
0095     int err;
0096 
0097     fib_cache = kzalloc(sizeof(*fib_cache), GFP_KERNEL);
0098     if (!fib_cache)
0099         goto err_kzalloc;
0100 
0101     memcpy(&fib_cache->key, key, sizeof(*key));
0102     fib_info_hold(fi);
0103     fib_cache->fi = fi;
0104     fib_cache->kern_dscp = dscp;
0105     fib_cache->kern_type = type;
0106 
0107     err = rhashtable_insert_fast(&sw->router->kern_fib_cache_ht,
0108                      &fib_cache->ht_node,
0109                      __prestera_kern_fib_cache_ht_params);
0110     if (err)
0111         goto err_ht_insert;
0112 
0113     return fib_cache;
0114 
0115 err_ht_insert:
0116     fib_info_put(fi);
0117     kfree(fib_cache);
0118 err_kzalloc:
0119     return NULL;
0120 }
0121 
0122 static void
0123 __prestera_k_arb_fib_lpm_offload_set(struct prestera_switch *sw,
0124                      struct prestera_kern_fib_cache *fc,
0125                      bool fail, bool offload, bool trap)
0126 {
0127     struct fib_rt_info fri;
0128 
0129     if (fc->key.addr.v != PRESTERA_IPV4)
0130         return;
0131 
0132     fri.fi = fc->fi;
0133     fri.tb_id = fc->key.kern_tb_id;
0134     fri.dst = fc->key.addr.u.ipv4;
0135     fri.dst_len = fc->key.prefix_len;
0136     fri.dscp = fc->kern_dscp;
0137     fri.type = fc->kern_type;
0138     /* flags begin */
0139     fri.offload = offload;
0140     fri.trap = trap;
0141     fri.offload_failed = fail;
0142     /* flags end */
0143     fib_alias_hw_flags_set(&init_net, &fri);
0144 }
0145 
0146 static int
0147 __prestera_pr_k_arb_fc_lpm_info_calc(struct prestera_switch *sw,
0148                      struct prestera_kern_fib_cache *fc)
0149 {
0150     memset(&fc->lpm_info, 0, sizeof(fc->lpm_info));
0151 
0152     switch (fc->fi->fib_type) {
0153     case RTN_UNICAST:
0154         fc->lpm_info.fib_type = PRESTERA_FIB_TYPE_TRAP;
0155         break;
0156     /* Unsupported. Leave it for kernel: */
0157     case RTN_BROADCAST:
0158     case RTN_MULTICAST:
0159     /* Routes we must trap by design: */
0160     case RTN_LOCAL:
0161     case RTN_UNREACHABLE:
0162     case RTN_PROHIBIT:
0163         fc->lpm_info.fib_type = PRESTERA_FIB_TYPE_TRAP;
0164         break;
0165     case RTN_BLACKHOLE:
0166         fc->lpm_info.fib_type = PRESTERA_FIB_TYPE_DROP;
0167         break;
0168     default:
0169         dev_err(sw->dev->dev, "Unsupported fib_type");
0170         return -EOPNOTSUPP;
0171     }
0172 
0173     fc->lpm_info.fib_key.addr = fc->key.addr;
0174     fc->lpm_info.fib_key.prefix_len = fc->key.prefix_len;
0175     fc->lpm_info.fib_key.tb_id = prestera_fix_tb_id(fc->key.kern_tb_id);
0176 
0177     return 0;
0178 }
0179 
0180 static int __prestera_k_arb_f_lpm_set(struct prestera_switch *sw,
0181                       struct prestera_kern_fib_cache *fc,
0182                       bool enabled)
0183 {
0184     struct prestera_fib_node *fib_node;
0185 
0186     fib_node = prestera_fib_node_find(sw, &fc->lpm_info.fib_key);
0187     if (fib_node)
0188         prestera_fib_node_destroy(sw, fib_node);
0189 
0190     if (!enabled)
0191         return 0;
0192 
0193     fib_node = prestera_fib_node_create(sw, &fc->lpm_info.fib_key,
0194                         fc->lpm_info.fib_type);
0195 
0196     if (!fib_node) {
0197         dev_err(sw->dev->dev, "fib_node=NULL %pI4n/%d kern_tb_id = %d",
0198             &fc->key.addr.u.ipv4, fc->key.prefix_len,
0199             fc->key.kern_tb_id);
0200         return -ENOENT;
0201     }
0202 
0203     return 0;
0204 }
0205 
0206 static int __prestera_k_arb_fc_apply(struct prestera_switch *sw,
0207                      struct prestera_kern_fib_cache *fc)
0208 {
0209     int err;
0210 
0211     err = __prestera_pr_k_arb_fc_lpm_info_calc(sw, fc);
0212     if (err)
0213         return err;
0214 
0215     err = __prestera_k_arb_f_lpm_set(sw, fc, fc->reachable);
0216     if (err) {
0217         __prestera_k_arb_fib_lpm_offload_set(sw, fc,
0218                              true, false, false);
0219         return err;
0220     }
0221 
0222     switch (fc->lpm_info.fib_type) {
0223     case PRESTERA_FIB_TYPE_TRAP:
0224         __prestera_k_arb_fib_lpm_offload_set(sw, fc, false,
0225                              false, fc->reachable);
0226         break;
0227     case PRESTERA_FIB_TYPE_DROP:
0228         __prestera_k_arb_fib_lpm_offload_set(sw, fc, false, true,
0229                              fc->reachable);
0230         break;
0231     case PRESTERA_FIB_TYPE_INVALID:
0232         break;
0233     }
0234 
0235     return 0;
0236 }
0237 
0238 static struct prestera_kern_fib_cache *
0239 __prestera_k_arb_util_fib_overlaps(struct prestera_switch *sw,
0240                    struct prestera_kern_fib_cache *fc)
0241 {
0242     struct prestera_kern_fib_cache_key fc_key;
0243     struct prestera_kern_fib_cache *rfc;
0244 
0245     /* TODO: parse kernel rules */
0246     rfc = NULL;
0247     if (fc->key.kern_tb_id == RT_TABLE_LOCAL) {
0248         memcpy(&fc_key, &fc->key, sizeof(fc_key));
0249         fc_key.kern_tb_id = RT_TABLE_MAIN;
0250         rfc = prestera_kern_fib_cache_find(sw, &fc_key);
0251     }
0252 
0253     return rfc;
0254 }
0255 
0256 static struct prestera_kern_fib_cache *
0257 __prestera_k_arb_util_fib_overlapped(struct prestera_switch *sw,
0258                      struct prestera_kern_fib_cache *fc)
0259 {
0260     struct prestera_kern_fib_cache_key fc_key;
0261     struct prestera_kern_fib_cache *rfc;
0262 
0263     /* TODO: parse kernel rules */
0264     rfc = NULL;
0265     if (fc->key.kern_tb_id == RT_TABLE_MAIN) {
0266         memcpy(&fc_key, &fc->key, sizeof(fc_key));
0267         fc_key.kern_tb_id = RT_TABLE_LOCAL;
0268         rfc = prestera_kern_fib_cache_find(sw, &fc_key);
0269     }
0270 
0271     return rfc;
0272 }
0273 
0274 static int
0275 prestera_k_arb_fib_evt(struct prestera_switch *sw,
0276                bool replace, /* replace or del */
0277                struct fib_entry_notifier_info *fen_info)
0278 {
0279     struct prestera_kern_fib_cache *tfib_cache, *bfib_cache; /* top/btm */
0280     struct prestera_kern_fib_cache_key fc_key;
0281     struct prestera_kern_fib_cache *fib_cache;
0282     int err;
0283 
0284     prestera_util_fen_info2fib_cache_key(fen_info, &fc_key);
0285     fib_cache = prestera_kern_fib_cache_find(sw, &fc_key);
0286     if (fib_cache) {
0287         fib_cache->reachable = false;
0288         err = __prestera_k_arb_fc_apply(sw, fib_cache);
0289         if (err)
0290             dev_err(sw->dev->dev,
0291                 "Applying destroyed fib_cache failed");
0292 
0293         bfib_cache = __prestera_k_arb_util_fib_overlaps(sw, fib_cache);
0294         tfib_cache = __prestera_k_arb_util_fib_overlapped(sw, fib_cache);
0295         if (!tfib_cache && bfib_cache) {
0296             bfib_cache->reachable = true;
0297             err = __prestera_k_arb_fc_apply(sw, bfib_cache);
0298             if (err)
0299                 dev_err(sw->dev->dev,
0300                     "Applying fib_cache btm failed");
0301         }
0302 
0303         prestera_kern_fib_cache_destroy(sw, fib_cache);
0304     }
0305 
0306     if (replace) {
0307         fib_cache = prestera_kern_fib_cache_create(sw, &fc_key,
0308                                fen_info->fi,
0309                                fen_info->dscp,
0310                                fen_info->type);
0311         if (!fib_cache) {
0312             dev_err(sw->dev->dev, "fib_cache == NULL");
0313             return -ENOENT;
0314         }
0315 
0316         bfib_cache = __prestera_k_arb_util_fib_overlaps(sw, fib_cache);
0317         tfib_cache = __prestera_k_arb_util_fib_overlapped(sw, fib_cache);
0318         if (!tfib_cache)
0319             fib_cache->reachable = true;
0320 
0321         if (bfib_cache) {
0322             bfib_cache->reachable = false;
0323             err = __prestera_k_arb_fc_apply(sw, bfib_cache);
0324             if (err)
0325                 dev_err(sw->dev->dev,
0326                     "Applying fib_cache btm failed");
0327         }
0328 
0329         err = __prestera_k_arb_fc_apply(sw, fib_cache);
0330         if (err)
0331             dev_err(sw->dev->dev, "Applying fib_cache failed");
0332     }
0333 
0334     return 0;
0335 }
0336 
0337 static int __prestera_inetaddr_port_event(struct net_device *port_dev,
0338                       unsigned long event,
0339                       struct netlink_ext_ack *extack)
0340 {
0341     struct prestera_port *port = netdev_priv(port_dev);
0342     struct prestera_rif_entry_key re_key = {};
0343     struct prestera_rif_entry *re;
0344     u32 kern_tb_id;
0345     int err;
0346 
0347     err = prestera_is_valid_mac_addr(port, port_dev->dev_addr);
0348     if (err) {
0349         NL_SET_ERR_MSG_MOD(extack, "RIF MAC must have the same prefix");
0350         return err;
0351     }
0352 
0353     kern_tb_id = l3mdev_fib_table(port_dev);
0354     re_key.iface.type = PRESTERA_IF_PORT_E;
0355     re_key.iface.dev_port.hw_dev_num  = port->dev_id;
0356     re_key.iface.dev_port.port_num  = port->hw_id;
0357     re = prestera_rif_entry_find(port->sw, &re_key);
0358 
0359     switch (event) {
0360     case NETDEV_UP:
0361         if (re) {
0362             NL_SET_ERR_MSG_MOD(extack, "RIF already exist");
0363             return -EEXIST;
0364         }
0365         re = prestera_rif_entry_create(port->sw, &re_key,
0366                            prestera_fix_tb_id(kern_tb_id),
0367                            port_dev->dev_addr);
0368         if (!re) {
0369             NL_SET_ERR_MSG_MOD(extack, "Can't create RIF");
0370             return -EINVAL;
0371         }
0372         dev_hold(port_dev);
0373         break;
0374     case NETDEV_DOWN:
0375         if (!re) {
0376             NL_SET_ERR_MSG_MOD(extack, "Can't find RIF");
0377             return -EEXIST;
0378         }
0379         prestera_rif_entry_destroy(port->sw, re);
0380         dev_put(port_dev);
0381         break;
0382     }
0383 
0384     return 0;
0385 }
0386 
0387 static int __prestera_inetaddr_event(struct prestera_switch *sw,
0388                      struct net_device *dev,
0389                      unsigned long event,
0390                      struct netlink_ext_ack *extack)
0391 {
0392     if (!prestera_netdev_check(dev) || netif_is_any_bridge_port(dev) ||
0393         netif_is_lag_port(dev))
0394         return 0;
0395 
0396     return __prestera_inetaddr_port_event(dev, event, extack);
0397 }
0398 
0399 static int __prestera_inetaddr_cb(struct notifier_block *nb,
0400                   unsigned long event, void *ptr)
0401 {
0402     struct in_ifaddr *ifa = (struct in_ifaddr *)ptr;
0403     struct net_device *dev = ifa->ifa_dev->dev;
0404     struct prestera_router *router = container_of(nb,
0405                               struct prestera_router,
0406                               inetaddr_nb);
0407     struct in_device *idev;
0408     int err = 0;
0409 
0410     if (event != NETDEV_DOWN)
0411         goto out;
0412 
0413     /* Ignore if this is not latest address */
0414     idev = __in_dev_get_rtnl(dev);
0415     if (idev && idev->ifa_list)
0416         goto out;
0417 
0418     err = __prestera_inetaddr_event(router->sw, dev, event, NULL);
0419 out:
0420     return notifier_from_errno(err);
0421 }
0422 
0423 static int __prestera_inetaddr_valid_cb(struct notifier_block *nb,
0424                     unsigned long event, void *ptr)
0425 {
0426     struct in_validator_info *ivi = (struct in_validator_info *)ptr;
0427     struct net_device *dev = ivi->ivi_dev->dev;
0428     struct prestera_router *router = container_of(nb,
0429                               struct prestera_router,
0430                               inetaddr_valid_nb);
0431     struct in_device *idev;
0432     int err = 0;
0433 
0434     if (event != NETDEV_UP)
0435         goto out;
0436 
0437     /* Ignore if this is not first address */
0438     idev = __in_dev_get_rtnl(dev);
0439     if (idev && idev->ifa_list)
0440         goto out;
0441 
0442     if (ipv4_is_multicast(ivi->ivi_addr)) {
0443         NL_SET_ERR_MSG_MOD(ivi->extack,
0444                    "Multicast addr on RIF is not supported");
0445         err = -EINVAL;
0446         goto out;
0447     }
0448 
0449     err = __prestera_inetaddr_event(router->sw, dev, event, ivi->extack);
0450 out:
0451     return notifier_from_errno(err);
0452 }
0453 
0454 struct prestera_fib_event_work {
0455     struct work_struct work;
0456     struct prestera_switch *sw;
0457     struct fib_entry_notifier_info fen_info;
0458     unsigned long event;
0459 };
0460 
0461 static void __prestera_router_fib_event_work(struct work_struct *work)
0462 {
0463     struct prestera_fib_event_work *fib_work =
0464             container_of(work, struct prestera_fib_event_work, work);
0465     struct prestera_switch *sw = fib_work->sw;
0466     int err;
0467 
0468     rtnl_lock();
0469 
0470     switch (fib_work->event) {
0471     case FIB_EVENT_ENTRY_REPLACE:
0472         err = prestera_k_arb_fib_evt(sw, true, &fib_work->fen_info);
0473         if (err)
0474             goto err_out;
0475 
0476         break;
0477     case FIB_EVENT_ENTRY_DEL:
0478         err = prestera_k_arb_fib_evt(sw, false, &fib_work->fen_info);
0479         if (err)
0480             goto err_out;
0481 
0482         break;
0483     }
0484 
0485     goto out;
0486 
0487 err_out:
0488     dev_err(sw->dev->dev, "Error when processing %pI4h/%d",
0489         &fib_work->fen_info.dst,
0490         fib_work->fen_info.dst_len);
0491 out:
0492     fib_info_put(fib_work->fen_info.fi);
0493     rtnl_unlock();
0494     kfree(fib_work);
0495 }
0496 
0497 /* Called with rcu_read_lock() */
0498 static int __prestera_router_fib_event(struct notifier_block *nb,
0499                        unsigned long event, void *ptr)
0500 {
0501     struct prestera_fib_event_work *fib_work;
0502     struct fib_entry_notifier_info *fen_info;
0503     struct fib_notifier_info *info = ptr;
0504     struct prestera_router *router;
0505 
0506     if (info->family != AF_INET)
0507         return NOTIFY_DONE;
0508 
0509     router = container_of(nb, struct prestera_router, fib_nb);
0510 
0511     switch (event) {
0512     case FIB_EVENT_ENTRY_REPLACE:
0513     case FIB_EVENT_ENTRY_DEL:
0514         fen_info = container_of(info, struct fib_entry_notifier_info,
0515                     info);
0516         if (!fen_info->fi)
0517             return NOTIFY_DONE;
0518 
0519         fib_work = kzalloc(sizeof(*fib_work), GFP_ATOMIC);
0520         if (WARN_ON(!fib_work))
0521             return NOTIFY_BAD;
0522 
0523         fib_info_hold(fen_info->fi);
0524         fib_work->fen_info = *fen_info;
0525         fib_work->event = event;
0526         fib_work->sw = router->sw;
0527         INIT_WORK(&fib_work->work, __prestera_router_fib_event_work);
0528         prestera_queue_work(&fib_work->work);
0529         break;
0530     default:
0531         return NOTIFY_DONE;
0532     }
0533 
0534     return NOTIFY_DONE;
0535 }
0536 
0537 int prestera_router_init(struct prestera_switch *sw)
0538 {
0539     struct prestera_router *router;
0540     int err;
0541 
0542     router = kzalloc(sizeof(*sw->router), GFP_KERNEL);
0543     if (!router)
0544         return -ENOMEM;
0545 
0546     sw->router = router;
0547     router->sw = sw;
0548 
0549     err = prestera_router_hw_init(sw);
0550     if (err)
0551         goto err_router_lib_init;
0552 
0553     err = rhashtable_init(&router->kern_fib_cache_ht,
0554                   &__prestera_kern_fib_cache_ht_params);
0555     if (err)
0556         goto err_kern_fib_cache_ht_init;
0557 
0558     router->inetaddr_valid_nb.notifier_call = __prestera_inetaddr_valid_cb;
0559     err = register_inetaddr_validator_notifier(&router->inetaddr_valid_nb);
0560     if (err)
0561         goto err_register_inetaddr_validator_notifier;
0562 
0563     router->inetaddr_nb.notifier_call = __prestera_inetaddr_cb;
0564     err = register_inetaddr_notifier(&router->inetaddr_nb);
0565     if (err)
0566         goto err_register_inetaddr_notifier;
0567 
0568     router->fib_nb.notifier_call = __prestera_router_fib_event;
0569     err = register_fib_notifier(&init_net, &router->fib_nb,
0570                     /* TODO: flush fib entries */ NULL, NULL);
0571     if (err)
0572         goto err_register_fib_notifier;
0573 
0574     return 0;
0575 
0576 err_register_fib_notifier:
0577     unregister_inetaddr_notifier(&router->inetaddr_nb);
0578 err_register_inetaddr_notifier:
0579     unregister_inetaddr_validator_notifier(&router->inetaddr_valid_nb);
0580 err_register_inetaddr_validator_notifier:
0581     rhashtable_destroy(&router->kern_fib_cache_ht);
0582 err_kern_fib_cache_ht_init:
0583     prestera_router_hw_fini(sw);
0584 err_router_lib_init:
0585     kfree(sw->router);
0586     return err;
0587 }
0588 
0589 void prestera_router_fini(struct prestera_switch *sw)
0590 {
0591     unregister_fib_notifier(&init_net, &sw->router->fib_nb);
0592     unregister_inetaddr_notifier(&sw->router->inetaddr_nb);
0593     unregister_inetaddr_validator_notifier(&sw->router->inetaddr_valid_nb);
0594     rhashtable_destroy(&sw->router->kern_fib_cache_ht);
0595     prestera_router_hw_fini(sw);
0596     kfree(sw->router);
0597     sw->router = NULL;
0598 }