Skip to content

Commit 430a049

Browse files
dsaherndavem330
authored andcommitted
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 <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent b513bd0 commit 430a049

File tree

2 files changed

+578
-24
lines changed

2 files changed

+578
-24
lines changed

include/net/nexthop.h

Lines changed: 97 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,9 @@ struct nh_config {
3535
struct in6_addr ipv6;
3636
} gw;
3737

38+
struct nlattr *nh_grp;
39+
u16 nh_grp_type;
40+
3841
struct nlattr *nh_encap;
3942
u16 nh_encap_type;
4043

@@ -56,20 +59,39 @@ struct nh_info {
5659
};
5760
};
5861

62+
struct nh_grp_entry {
63+
struct nexthop *nh;
64+
u8 weight;
65+
atomic_t upper_bound;
66+
67+
struct list_head nh_list;
68+
struct nexthop *nh_parent; /* nexthop of group with this entry */
69+
};
70+
71+
struct nh_group {
72+
u16 num_nh;
73+
bool mpath;
74+
bool has_v4;
75+
struct nh_grp_entry nh_entries[0];
76+
};
77+
5978
struct nexthop {
6079
struct rb_node rb_node; /* entry on netns rbtree */
80+
struct list_head grp_list; /* nh group entries using this nh */
6181
struct net *net;
6282

6383
u32 id;
6484

6585
u8 protocol; /* app managing this nh */
6686
u8 nh_flags;
87+
bool is_group;
6788

6889
refcount_t refcnt;
6990
struct rcu_head rcu;
7091

7192
union {
7293
struct nh_info __rcu *nh_info;
94+
struct nh_group __rcu *nh_grp;
7395
};
7496
};
7597

@@ -88,12 +110,86 @@ static inline void nexthop_put(struct nexthop *nh)
88110
call_rcu(&nh->rcu, nexthop_free_rcu);
89111
}
90112

113+
static inline bool nexthop_is_multipath(const struct nexthop *nh)
114+
{
115+
if (nh->is_group) {
116+
struct nh_group *nh_grp;
117+
118+
nh_grp = rcu_dereference_rtnl(nh->nh_grp);
119+
return nh_grp->mpath;
120+
}
121+
return false;
122+
}
123+
124+
struct nexthop *nexthop_select_path(struct nexthop *nh, int hash);
125+
126+
static inline unsigned int nexthop_num_path(const struct nexthop *nh)
127+
{
128+
unsigned int rc = 1;
129+
130+
if (nexthop_is_multipath(nh)) {
131+
struct nh_group *nh_grp;
132+
133+
nh_grp = rcu_dereference_rtnl(nh->nh_grp);
134+
rc = nh_grp->num_nh;
135+
} else {
136+
const struct nh_info *nhi;
137+
138+
nhi = rcu_dereference_rtnl(nh->nh_info);
139+
if (nhi->reject_nh)
140+
rc = 0;
141+
}
142+
143+
return rc;
144+
}
145+
146+
static inline
147+
struct nexthop *nexthop_mpath_select(const struct nexthop *nh, int nhsel)
148+
{
149+
const struct nh_group *nhg = rcu_dereference_rtnl(nh->nh_grp);
150+
151+
/* for_nexthops macros in fib_semantics.c grabs a pointer to
152+
* the nexthop before checking nhsel
153+
*/
154+
if (nhsel > nhg->num_nh)
155+
return NULL;
156+
157+
return nhg->nh_entries[nhsel].nh;
158+
}
159+
160+
static inline
161+
int nexthop_mpath_fill_node(struct sk_buff *skb, struct nexthop *nh)
162+
{
163+
struct nh_group *nhg = rtnl_dereference(nh->nh_grp);
164+
int i;
165+
166+
for (i = 0; i < nhg->num_nh; i++) {
167+
struct nexthop *nhe = nhg->nh_entries[i].nh;
168+
struct nh_info *nhi = rcu_dereference_rtnl(nhe->nh_info);
169+
struct fib_nh_common *nhc = &nhi->fib_nhc;
170+
int weight = nhg->nh_entries[i].weight;
171+
172+
if (fib_add_nexthop(skb, nhc, weight) < 0)
173+
return -EMSGSIZE;
174+
}
175+
176+
return 0;
177+
}
178+
91179
/* called with rcu lock */
92180
static inline bool nexthop_is_blackhole(const struct nexthop *nh)
93181
{
94182
const struct nh_info *nhi;
95183

96-
nhi = rcu_dereference(nh->nh_info);
184+
if (nexthop_is_multipath(nh)) {
185+
if (nexthop_num_path(nh) > 1)
186+
return false;
187+
nh = nexthop_mpath_select(nh, 0);
188+
if (!nh)
189+
return false;
190+
}
191+
192+
nhi = rcu_dereference_rtnl(nh->nh_info);
97193
return nhi->reject_nh;
98194
}
99195
#endif

0 commit comments

Comments
 (0)