|
@@ -630,31 +630,35 @@ static bool rt6_qualify_for_ecmp(struct rt6_info *rt)
|
|
RTF_GATEWAY;
|
|
RTF_GATEWAY;
|
|
}
|
|
}
|
|
|
|
|
|
-static int fib6_commit_metrics(struct dst_entry *dst,
|
|
|
|
- struct nlattr *mx, int mx_len)
|
|
|
|
|
|
+static void fib6_copy_metrics(u32 *mp, const struct mx6_config *mxc)
|
|
{
|
|
{
|
|
- bool dst_host = dst->flags & DST_HOST;
|
|
|
|
- struct nlattr *nla;
|
|
|
|
- int remaining;
|
|
|
|
- u32 *mp;
|
|
|
|
|
|
+ int i;
|
|
|
|
|
|
- mp = dst_host ? dst_metrics_write_ptr(dst) :
|
|
|
|
- kzalloc(sizeof(u32) * RTAX_MAX, GFP_ATOMIC);
|
|
|
|
- if (unlikely(!mp))
|
|
|
|
- return -ENOMEM;
|
|
|
|
- if (!dst_host)
|
|
|
|
- dst_init_metrics(dst, mp, 0);
|
|
|
|
|
|
+ for (i = 0; i < RTAX_MAX; i++) {
|
|
|
|
+ if (test_bit(i, mxc->mx_valid))
|
|
|
|
+ mp[i] = mxc->mx[i];
|
|
|
|
+ }
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+static int fib6_commit_metrics(struct dst_entry *dst, struct mx6_config *mxc)
|
|
|
|
+{
|
|
|
|
+ if (!mxc->mx)
|
|
|
|
+ return 0;
|
|
|
|
|
|
- nla_for_each_attr(nla, mx, mx_len, remaining) {
|
|
|
|
- int type = nla_type(nla);
|
|
|
|
|
|
+ if (dst->flags & DST_HOST) {
|
|
|
|
+ u32 *mp = dst_metrics_write_ptr(dst);
|
|
|
|
|
|
- if (type) {
|
|
|
|
- if (type > RTAX_MAX)
|
|
|
|
- return -EINVAL;
|
|
|
|
|
|
+ if (unlikely(!mp))
|
|
|
|
+ return -ENOMEM;
|
|
|
|
|
|
- mp[type - 1] = nla_get_u32(nla);
|
|
|
|
- }
|
|
|
|
|
|
+ fib6_copy_metrics(mp, mxc);
|
|
|
|
+ } else {
|
|
|
|
+ dst_init_metrics(dst, mxc->mx, false);
|
|
|
|
+
|
|
|
|
+ /* We've stolen mx now. */
|
|
|
|
+ mxc->mx = NULL;
|
|
}
|
|
}
|
|
|
|
+
|
|
return 0;
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
|
|
@@ -663,7 +667,7 @@ static int fib6_commit_metrics(struct dst_entry *dst,
|
|
*/
|
|
*/
|
|
|
|
|
|
static int fib6_add_rt2node(struct fib6_node *fn, struct rt6_info *rt,
|
|
static int fib6_add_rt2node(struct fib6_node *fn, struct rt6_info *rt,
|
|
- struct nl_info *info, struct nlattr *mx, int mx_len)
|
|
|
|
|
|
+ struct nl_info *info, struct mx6_config *mxc)
|
|
{
|
|
{
|
|
struct rt6_info *iter = NULL;
|
|
struct rt6_info *iter = NULL;
|
|
struct rt6_info **ins;
|
|
struct rt6_info **ins;
|
|
@@ -772,11 +776,10 @@ static int fib6_add_rt2node(struct fib6_node *fn, struct rt6_info *rt,
|
|
pr_warn("NLM_F_CREATE should be set when creating new route\n");
|
|
pr_warn("NLM_F_CREATE should be set when creating new route\n");
|
|
|
|
|
|
add:
|
|
add:
|
|
- if (mx) {
|
|
|
|
- err = fib6_commit_metrics(&rt->dst, mx, mx_len);
|
|
|
|
- if (err)
|
|
|
|
- return err;
|
|
|
|
- }
|
|
|
|
|
|
+ err = fib6_commit_metrics(&rt->dst, mxc);
|
|
|
|
+ if (err)
|
|
|
|
+ return err;
|
|
|
|
+
|
|
rt->dst.rt6_next = iter;
|
|
rt->dst.rt6_next = iter;
|
|
*ins = rt;
|
|
*ins = rt;
|
|
rt->rt6i_node = fn;
|
|
rt->rt6i_node = fn;
|
|
@@ -796,11 +799,11 @@ add:
|
|
pr_warn("NLM_F_REPLACE set, but no existing node found!\n");
|
|
pr_warn("NLM_F_REPLACE set, but no existing node found!\n");
|
|
return -ENOENT;
|
|
return -ENOENT;
|
|
}
|
|
}
|
|
- if (mx) {
|
|
|
|
- err = fib6_commit_metrics(&rt->dst, mx, mx_len);
|
|
|
|
- if (err)
|
|
|
|
- return err;
|
|
|
|
- }
|
|
|
|
|
|
+
|
|
|
|
+ err = fib6_commit_metrics(&rt->dst, mxc);
|
|
|
|
+ if (err)
|
|
|
|
+ return err;
|
|
|
|
+
|
|
*ins = rt;
|
|
*ins = rt;
|
|
rt->rt6i_node = fn;
|
|
rt->rt6i_node = fn;
|
|
rt->dst.rt6_next = iter->dst.rt6_next;
|
|
rt->dst.rt6_next = iter->dst.rt6_next;
|
|
@@ -837,8 +840,8 @@ void fib6_force_start_gc(struct net *net)
|
|
* with source addr info in sub-trees
|
|
* with source addr info in sub-trees
|
|
*/
|
|
*/
|
|
|
|
|
|
-int fib6_add(struct fib6_node *root, struct rt6_info *rt, struct nl_info *info,
|
|
|
|
- struct nlattr *mx, int mx_len)
|
|
|
|
|
|
+int fib6_add(struct fib6_node *root, struct rt6_info *rt,
|
|
|
|
+ struct nl_info *info, struct mx6_config *mxc)
|
|
{
|
|
{
|
|
struct fib6_node *fn, *pn = NULL;
|
|
struct fib6_node *fn, *pn = NULL;
|
|
int err = -ENOMEM;
|
|
int err = -ENOMEM;
|
|
@@ -933,7 +936,7 @@ int fib6_add(struct fib6_node *root, struct rt6_info *rt, struct nl_info *info,
|
|
}
|
|
}
|
|
#endif
|
|
#endif
|
|
|
|
|
|
- err = fib6_add_rt2node(fn, rt, info, mx, mx_len);
|
|
|
|
|
|
+ err = fib6_add_rt2node(fn, rt, info, mxc);
|
|
if (!err) {
|
|
if (!err) {
|
|
fib6_start_gc(info->nl_net, rt);
|
|
fib6_start_gc(info->nl_net, rt);
|
|
if (!(rt->rt6i_flags & RTF_CACHE))
|
|
if (!(rt->rt6i_flags & RTF_CACHE))
|