root/include/net/nexthop.h

/* [<][>][^][v][top][bottom][index][help] */

INCLUDED FROM


DEFINITIONS

This source file includes following definitions.
  1. nexthop_get
  2. nexthop_put
  3. nexthop_cmp
  4. nexthop_is_multipath
  5. nexthop_num_path
  6. nexthop_mpath_select
  7. nexthop_mpath_fill_node
  8. nexthop_is_blackhole
  9. nexthop_path_fib_result
  10. nexthop_fib_nhc
  11. nexthop_uses_dev
  12. fib_info_num_path
  13. fib_info_nhc
  14. fib_info_nh
  15. nexthop_fib6_nh
  16. fib6_info_nh_dev
  17. nexthop_path_fib6_result

   1 /* SPDX-License-Identifier: GPL-2.0 */
   2 /*
   3  * Generic nexthop implementation
   4  *
   5  * Copyright (c) 2017-19 Cumulus Networks
   6  * Copyright (c) 2017-19 David Ahern <dsa@cumulusnetworks.com>
   7  */
   8 
   9 #ifndef __LINUX_NEXTHOP_H
  10 #define __LINUX_NEXTHOP_H
  11 
  12 #include <linux/netdevice.h>
  13 #include <linux/route.h>
  14 #include <linux/types.h>
  15 #include <net/ip_fib.h>
  16 #include <net/ip6_fib.h>
  17 #include <net/netlink.h>
  18 
  19 #define NEXTHOP_VALID_USER_FLAGS RTNH_F_ONLINK
  20 
  21 struct nexthop;
  22 
  23 struct nh_config {
  24         u32             nh_id;
  25 
  26         u8              nh_family;
  27         u8              nh_protocol;
  28         u8              nh_blackhole;
  29         u32             nh_flags;
  30 
  31         int             nh_ifindex;
  32         struct net_device *dev;
  33 
  34         union {
  35                 __be32          ipv4;
  36                 struct in6_addr ipv6;
  37         } gw;
  38 
  39         struct nlattr   *nh_grp;
  40         u16             nh_grp_type;
  41 
  42         struct nlattr   *nh_encap;
  43         u16             nh_encap_type;
  44 
  45         u32             nlflags;
  46         struct nl_info  nlinfo;
  47 };
  48 
  49 struct nh_info {
  50         struct hlist_node       dev_hash;    /* entry on netns devhash */
  51         struct nexthop          *nh_parent;
  52 
  53         u8                      family;
  54         bool                    reject_nh;
  55 
  56         union {
  57                 struct fib_nh_common    fib_nhc;
  58                 struct fib_nh           fib_nh;
  59                 struct fib6_nh          fib6_nh;
  60         };
  61 };
  62 
  63 struct nh_grp_entry {
  64         struct nexthop  *nh;
  65         u8              weight;
  66         atomic_t        upper_bound;
  67 
  68         struct list_head nh_list;
  69         struct nexthop  *nh_parent;  /* nexthop of group with this entry */
  70 };
  71 
  72 struct nh_group {
  73         struct nh_group         *spare; /* spare group for removals */
  74         u16                     num_nh;
  75         bool                    mpath;
  76         bool                    has_v4;
  77         struct nh_grp_entry     nh_entries[0];
  78 };
  79 
  80 struct nexthop {
  81         struct rb_node          rb_node;    /* entry on netns rbtree */
  82         struct list_head        fi_list;    /* v4 entries using nh */
  83         struct list_head        f6i_list;   /* v6 entries using nh */
  84         struct list_head        grp_list;   /* nh group entries using this nh */
  85         struct net              *net;
  86 
  87         u32                     id;
  88 
  89         u8                      protocol;   /* app managing this nh */
  90         u8                      nh_flags;
  91         bool                    is_group;
  92 
  93         refcount_t              refcnt;
  94         struct rcu_head         rcu;
  95 
  96         union {
  97                 struct nh_info  __rcu *nh_info;
  98                 struct nh_group __rcu *nh_grp;
  99         };
 100 };
 101 
 102 /* caller is holding rcu or rtnl; no reference taken to nexthop */
 103 struct nexthop *nexthop_find_by_id(struct net *net, u32 id);
 104 void nexthop_free_rcu(struct rcu_head *head);
 105 
 106 static inline bool nexthop_get(struct nexthop *nh)
 107 {
 108         return refcount_inc_not_zero(&nh->refcnt);
 109 }
 110 
 111 static inline void nexthop_put(struct nexthop *nh)
 112 {
 113         if (refcount_dec_and_test(&nh->refcnt))
 114                 call_rcu(&nh->rcu, nexthop_free_rcu);
 115 }
 116 
 117 static inline bool nexthop_cmp(const struct nexthop *nh1,
 118                                const struct nexthop *nh2)
 119 {
 120         return nh1 == nh2;
 121 }
 122 
 123 static inline bool nexthop_is_multipath(const struct nexthop *nh)
 124 {
 125         if (nh->is_group) {
 126                 struct nh_group *nh_grp;
 127 
 128                 nh_grp = rcu_dereference_rtnl(nh->nh_grp);
 129                 return nh_grp->mpath;
 130         }
 131         return false;
 132 }
 133 
 134 struct nexthop *nexthop_select_path(struct nexthop *nh, int hash);
 135 
 136 static inline unsigned int nexthop_num_path(const struct nexthop *nh)
 137 {
 138         unsigned int rc = 1;
 139 
 140         if (nh->is_group) {
 141                 struct nh_group *nh_grp;
 142 
 143                 nh_grp = rcu_dereference_rtnl(nh->nh_grp);
 144                 if (nh_grp->mpath)
 145                         rc = nh_grp->num_nh;
 146         }
 147 
 148         return rc;
 149 }
 150 
 151 static inline
 152 struct nexthop *nexthop_mpath_select(const struct nh_group *nhg, int nhsel)
 153 {
 154         /* for_nexthops macros in fib_semantics.c grabs a pointer to
 155          * the nexthop before checking nhsel
 156          */
 157         if (nhsel >= nhg->num_nh)
 158                 return NULL;
 159 
 160         return nhg->nh_entries[nhsel].nh;
 161 }
 162 
 163 static inline
 164 int nexthop_mpath_fill_node(struct sk_buff *skb, struct nexthop *nh,
 165                             u8 rt_family)
 166 {
 167         struct nh_group *nhg = rtnl_dereference(nh->nh_grp);
 168         int i;
 169 
 170         for (i = 0; i < nhg->num_nh; i++) {
 171                 struct nexthop *nhe = nhg->nh_entries[i].nh;
 172                 struct nh_info *nhi = rcu_dereference_rtnl(nhe->nh_info);
 173                 struct fib_nh_common *nhc = &nhi->fib_nhc;
 174                 int weight = nhg->nh_entries[i].weight;
 175 
 176                 if (fib_add_nexthop(skb, nhc, weight, rt_family) < 0)
 177                         return -EMSGSIZE;
 178         }
 179 
 180         return 0;
 181 }
 182 
 183 /* called with rcu lock */
 184 static inline bool nexthop_is_blackhole(const struct nexthop *nh)
 185 {
 186         const struct nh_info *nhi;
 187 
 188         if (nh->is_group) {
 189                 struct nh_group *nh_grp;
 190 
 191                 nh_grp = rcu_dereference_rtnl(nh->nh_grp);
 192                 if (nh_grp->num_nh > 1)
 193                         return false;
 194 
 195                 nh = nh_grp->nh_entries[0].nh;
 196         }
 197 
 198         nhi = rcu_dereference_rtnl(nh->nh_info);
 199         return nhi->reject_nh;
 200 }
 201 
 202 static inline void nexthop_path_fib_result(struct fib_result *res, int hash)
 203 {
 204         struct nh_info *nhi;
 205         struct nexthop *nh;
 206 
 207         nh = nexthop_select_path(res->fi->nh, hash);
 208         nhi = rcu_dereference(nh->nh_info);
 209         res->nhc = &nhi->fib_nhc;
 210 }
 211 
 212 /* called with rcu read lock or rtnl held */
 213 static inline
 214 struct fib_nh_common *nexthop_fib_nhc(struct nexthop *nh, int nhsel)
 215 {
 216         struct nh_info *nhi;
 217 
 218         BUILD_BUG_ON(offsetof(struct fib_nh, nh_common) != 0);
 219         BUILD_BUG_ON(offsetof(struct fib6_nh, nh_common) != 0);
 220 
 221         if (nh->is_group) {
 222                 struct nh_group *nh_grp;
 223 
 224                 nh_grp = rcu_dereference_rtnl(nh->nh_grp);
 225                 if (nh_grp->mpath) {
 226                         nh = nexthop_mpath_select(nh_grp, nhsel);
 227                         if (!nh)
 228                                 return NULL;
 229                 }
 230         }
 231 
 232         nhi = rcu_dereference_rtnl(nh->nh_info);
 233         return &nhi->fib_nhc;
 234 }
 235 
 236 static inline bool nexthop_uses_dev(const struct nexthop *nh,
 237                                     const struct net_device *dev)
 238 {
 239         struct nh_info *nhi;
 240 
 241         if (nh->is_group) {
 242                 struct nh_group *nhg = rcu_dereference(nh->nh_grp);
 243                 int i;
 244 
 245                 for (i = 0; i < nhg->num_nh; i++) {
 246                         struct nexthop *nhe = nhg->nh_entries[i].nh;
 247 
 248                         nhi = rcu_dereference(nhe->nh_info);
 249                         if (nhc_l3mdev_matches_dev(&nhi->fib_nhc, dev))
 250                                 return true;
 251                 }
 252         } else {
 253                 nhi = rcu_dereference(nh->nh_info);
 254                 if (nhc_l3mdev_matches_dev(&nhi->fib_nhc, dev))
 255                         return true;
 256         }
 257 
 258         return false;
 259 }
 260 
 261 static inline unsigned int fib_info_num_path(const struct fib_info *fi)
 262 {
 263         if (unlikely(fi->nh))
 264                 return nexthop_num_path(fi->nh);
 265 
 266         return fi->fib_nhs;
 267 }
 268 
 269 int fib_check_nexthop(struct nexthop *nh, u8 scope,
 270                       struct netlink_ext_ack *extack);
 271 
 272 static inline struct fib_nh_common *fib_info_nhc(struct fib_info *fi, int nhsel)
 273 {
 274         if (unlikely(fi->nh))
 275                 return nexthop_fib_nhc(fi->nh, nhsel);
 276 
 277         return &fi->fib_nh[nhsel].nh_common;
 278 }
 279 
 280 /* only used when fib_nh is built into fib_info */
 281 static inline struct fib_nh *fib_info_nh(struct fib_info *fi, int nhsel)
 282 {
 283         WARN_ON(fi->nh);
 284 
 285         return &fi->fib_nh[nhsel];
 286 }
 287 
 288 /*
 289  * IPv6 variants
 290  */
 291 int fib6_check_nexthop(struct nexthop *nh, struct fib6_config *cfg,
 292                        struct netlink_ext_ack *extack);
 293 
 294 static inline struct fib6_nh *nexthop_fib6_nh(struct nexthop *nh)
 295 {
 296         struct nh_info *nhi;
 297 
 298         if (nh->is_group) {
 299                 struct nh_group *nh_grp;
 300 
 301                 nh_grp = rcu_dereference_rtnl(nh->nh_grp);
 302                 nh = nexthop_mpath_select(nh_grp, 0);
 303                 if (!nh)
 304                         return NULL;
 305         }
 306 
 307         nhi = rcu_dereference_rtnl(nh->nh_info);
 308         if (nhi->family == AF_INET6)
 309                 return &nhi->fib6_nh;
 310 
 311         return NULL;
 312 }
 313 
 314 static inline struct net_device *fib6_info_nh_dev(struct fib6_info *f6i)
 315 {
 316         struct fib6_nh *fib6_nh;
 317 
 318         fib6_nh = f6i->nh ? nexthop_fib6_nh(f6i->nh) : f6i->fib6_nh;
 319         return fib6_nh->fib_nh_dev;
 320 }
 321 
 322 static inline void nexthop_path_fib6_result(struct fib6_result *res, int hash)
 323 {
 324         struct nexthop *nh = res->f6i->nh;
 325         struct nh_info *nhi;
 326 
 327         nh = nexthop_select_path(nh, hash);
 328 
 329         nhi = rcu_dereference_rtnl(nh->nh_info);
 330         if (nhi->reject_nh) {
 331                 res->fib6_type = RTN_BLACKHOLE;
 332                 res->fib6_flags |= RTF_REJECT;
 333                 res->nh = nexthop_fib6_nh(nh);
 334         } else {
 335                 res->nh = &nhi->fib6_nh;
 336         }
 337 }
 338 
 339 int nexthop_for_each_fib6_nh(struct nexthop *nh,
 340                              int (*cb)(struct fib6_nh *nh, void *arg),
 341                              void *arg);
 342 #endif

/* [<][>][^][v][top][bottom][index][help] */