mirror of
https://github.com/armbian/linux-cix.git
synced 2026-01-06 12:30:45 -08:00
nexthop: Add support for nexthop groups
Allow the creation of nexthop groups which reference other nexthop
objects to create multipath routes:
+--------------+
+------------+ +--------------+ |
| nh nh_grp --->| nh_grp_entry |-+
+------------+ +---------|----+
^ | | +------------+
+----------------+ +--->| nh, weight |
nh_parent +------------+
A group entry points to a nexthop with a weight for that hop within the
group. The nexthop has a list_head, grp_list, for tracking which groups
it is a member of and the group entry has a reference back to the parent.
The grp_list is used when a nexthop is deleted - to efficiently remove
it from groups using it.
If a nexthop group spec is given, no other attributes can be set. Each
nexthop id in a group spec must already exist.
Similar to single nexthops, the specification of a nexthop group can be
updated so that data is managed with rcu locking.
Add path selection function to account for multiple paths and add
ipv{4,6}_good_nh helpers to know that if a neighbor entry exists it is
in a good state.
Update NETDEV event handling to rebalance multipath nexthop groups if
a nexthop is deleted due to a link event (down or unregister).
When a nexthop is removed any groups using it are updated. Groups using a
nexthop a tracked via a grp_list.
Nexthop dumps can be limited to groups only by adding NHA_GROUPS to the
request.
Signed-off-by: David Ahern <dsahern@gmail.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
committed by
David S. Miller
parent
b513bd035f
commit
430a049190
@@ -35,6 +35,9 @@ struct nh_config {
|
||||
struct in6_addr ipv6;
|
||||
} gw;
|
||||
|
||||
struct nlattr *nh_grp;
|
||||
u16 nh_grp_type;
|
||||
|
||||
struct nlattr *nh_encap;
|
||||
u16 nh_encap_type;
|
||||
|
||||
@@ -56,20 +59,39 @@ struct nh_info {
|
||||
};
|
||||
};
|
||||
|
||||
struct nh_grp_entry {
|
||||
struct nexthop *nh;
|
||||
u8 weight;
|
||||
atomic_t upper_bound;
|
||||
|
||||
struct list_head nh_list;
|
||||
struct nexthop *nh_parent; /* nexthop of group with this entry */
|
||||
};
|
||||
|
||||
struct nh_group {
|
||||
u16 num_nh;
|
||||
bool mpath;
|
||||
bool has_v4;
|
||||
struct nh_grp_entry nh_entries[0];
|
||||
};
|
||||
|
||||
struct nexthop {
|
||||
struct rb_node rb_node; /* entry on netns rbtree */
|
||||
struct list_head grp_list; /* nh group entries using this nh */
|
||||
struct net *net;
|
||||
|
||||
u32 id;
|
||||
|
||||
u8 protocol; /* app managing this nh */
|
||||
u8 nh_flags;
|
||||
bool is_group;
|
||||
|
||||
refcount_t refcnt;
|
||||
struct rcu_head rcu;
|
||||
|
||||
union {
|
||||
struct nh_info __rcu *nh_info;
|
||||
struct nh_group __rcu *nh_grp;
|
||||
};
|
||||
};
|
||||
|
||||
@@ -88,12 +110,86 @@ static inline void nexthop_put(struct nexthop *nh)
|
||||
call_rcu(&nh->rcu, nexthop_free_rcu);
|
||||
}
|
||||
|
||||
static inline bool nexthop_is_multipath(const struct nexthop *nh)
|
||||
{
|
||||
if (nh->is_group) {
|
||||
struct nh_group *nh_grp;
|
||||
|
||||
nh_grp = rcu_dereference_rtnl(nh->nh_grp);
|
||||
return nh_grp->mpath;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
struct nexthop *nexthop_select_path(struct nexthop *nh, int hash);
|
||||
|
||||
static inline unsigned int nexthop_num_path(const struct nexthop *nh)
|
||||
{
|
||||
unsigned int rc = 1;
|
||||
|
||||
if (nexthop_is_multipath(nh)) {
|
||||
struct nh_group *nh_grp;
|
||||
|
||||
nh_grp = rcu_dereference_rtnl(nh->nh_grp);
|
||||
rc = nh_grp->num_nh;
|
||||
} else {
|
||||
const struct nh_info *nhi;
|
||||
|
||||
nhi = rcu_dereference_rtnl(nh->nh_info);
|
||||
if (nhi->reject_nh)
|
||||
rc = 0;
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
static inline
|
||||
struct nexthop *nexthop_mpath_select(const struct nexthop *nh, int nhsel)
|
||||
{
|
||||
const struct nh_group *nhg = rcu_dereference_rtnl(nh->nh_grp);
|
||||
|
||||
/* for_nexthops macros in fib_semantics.c grabs a pointer to
|
||||
* the nexthop before checking nhsel
|
||||
*/
|
||||
if (nhsel > nhg->num_nh)
|
||||
return NULL;
|
||||
|
||||
return nhg->nh_entries[nhsel].nh;
|
||||
}
|
||||
|
||||
static inline
|
||||
int nexthop_mpath_fill_node(struct sk_buff *skb, struct nexthop *nh)
|
||||
{
|
||||
struct nh_group *nhg = rtnl_dereference(nh->nh_grp);
|
||||
int i;
|
||||
|
||||
for (i = 0; i < nhg->num_nh; i++) {
|
||||
struct nexthop *nhe = nhg->nh_entries[i].nh;
|
||||
struct nh_info *nhi = rcu_dereference_rtnl(nhe->nh_info);
|
||||
struct fib_nh_common *nhc = &nhi->fib_nhc;
|
||||
int weight = nhg->nh_entries[i].weight;
|
||||
|
||||
if (fib_add_nexthop(skb, nhc, weight) < 0)
|
||||
return -EMSGSIZE;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* called with rcu lock */
|
||||
static inline bool nexthop_is_blackhole(const struct nexthop *nh)
|
||||
{
|
||||
const struct nh_info *nhi;
|
||||
|
||||
nhi = rcu_dereference(nh->nh_info);
|
||||
if (nexthop_is_multipath(nh)) {
|
||||
if (nexthop_num_path(nh) > 1)
|
||||
return false;
|
||||
nh = nexthop_mpath_select(nh, 0);
|
||||
if (!nh)
|
||||
return false;
|
||||
}
|
||||
|
||||
nhi = rcu_dereference_rtnl(nh->nh_info);
|
||||
return nhi->reject_nh;
|
||||
}
|
||||
#endif
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user