Commit 5a4d148f authored by David S. Miller's avatar David S. Miller

Merge branch 'per-nexthop-offload'

Jiri Pirko says:

====================
ipv4: fib: Provide per-nexthop offload indication

Ido says:

Offload indication for IPv4 routes is currently set in the FIB info's
flags. When multipath routes are employed, this can lead to a route being
marked as offloaded although only one of its nexthops is actually
offloaded.

Instead, this patchset aims to proivde a higher resolution for the offload
indication and report it on a per-nexthop basis.

Example output from patched iproute:

$ ip route show 192.168.200.0/24
192.168.200.0/24
        nexthop via 192.168.100.2 dev enp3s0np7 weight 1 offload
        nexthop via 192.168.101.3 dev enp3s0np8 weight 1

And once the second gateway is resolved:

$ ip route show 192.168.200.0/24
192.168.200.0/24
        nexthop via 192.168.100.2 dev enp3s0np7 weight 1 offload
        nexthop via 192.168.101.3 dev enp3s0np8 weight 1 offload

First patch teaches the kernel to look for the offload indication in the
nexthop flags. Patches 2-5 adjust current capable drivers to provide
offload indication on a per-nexthop basis. Last patch removes no longer
used functions to set offload indication in the FIB info's flags.
====================
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents 9820355f 2202e35d
...@@ -394,7 +394,6 @@ struct mlxsw_sp_fib_entry { ...@@ -394,7 +394,6 @@ struct mlxsw_sp_fib_entry {
enum mlxsw_sp_fib_entry_type type; enum mlxsw_sp_fib_entry_type type;
struct list_head nexthop_group_node; struct list_head nexthop_group_node;
struct mlxsw_sp_nexthop_group *nh_group; struct mlxsw_sp_nexthop_group *nh_group;
bool offloaded;
}; };
struct mlxsw_sp_fib4_entry { struct mlxsw_sp_fib4_entry {
...@@ -1653,6 +1652,24 @@ mlxsw_sp_nexthop_fib_entries_update(struct mlxsw_sp *mlxsw_sp, ...@@ -1653,6 +1652,24 @@ mlxsw_sp_nexthop_fib_entries_update(struct mlxsw_sp *mlxsw_sp,
return 0; return 0;
} }
static void
mlxsw_sp_fib_entry_offload_refresh(struct mlxsw_sp_fib_entry *fib_entry,
enum mlxsw_reg_ralue_op op, int err);
static void
mlxsw_sp_nexthop_fib_entries_refresh(struct mlxsw_sp_nexthop_group *nh_grp)
{
enum mlxsw_reg_ralue_op op = MLXSW_REG_RALUE_OP_WRITE_WRITE;
struct mlxsw_sp_fib_entry *fib_entry;
list_for_each_entry(fib_entry, &nh_grp->fib_list, nexthop_group_node) {
if (!mlxsw_sp_fib_node_entry_is_first(fib_entry->fib_node,
fib_entry))
continue;
mlxsw_sp_fib_entry_offload_refresh(fib_entry, op, 0);
}
}
static void static void
mlxsw_sp_nexthop_group_refresh(struct mlxsw_sp *mlxsw_sp, mlxsw_sp_nexthop_group_refresh(struct mlxsw_sp *mlxsw_sp,
struct mlxsw_sp_nexthop_group *nh_grp) struct mlxsw_sp_nexthop_group *nh_grp)
...@@ -1740,6 +1757,10 @@ mlxsw_sp_nexthop_group_refresh(struct mlxsw_sp *mlxsw_sp, ...@@ -1740,6 +1757,10 @@ mlxsw_sp_nexthop_group_refresh(struct mlxsw_sp *mlxsw_sp,
dev_warn(mlxsw_sp->bus_info->dev, "Failed to mass-update adjacency index for nexthop group.\n"); dev_warn(mlxsw_sp->bus_info->dev, "Failed to mass-update adjacency index for nexthop group.\n");
goto set_trap; goto set_trap;
} }
/* Offload state within the group changed, so update the flags. */
mlxsw_sp_nexthop_fib_entries_refresh(nh_grp);
return; return;
set_trap: set_trap:
...@@ -2103,13 +2124,45 @@ mlxsw_sp_fib_entry_should_offload(const struct mlxsw_sp_fib_entry *fib_entry) ...@@ -2103,13 +2124,45 @@ mlxsw_sp_fib_entry_should_offload(const struct mlxsw_sp_fib_entry *fib_entry)
} }
} }
static void mlxsw_sp_fib_entry_offload_set(struct mlxsw_sp_fib_entry *fib_entry) static void
mlxsw_sp_fib4_entry_offload_set(struct mlxsw_sp_fib_entry *fib_entry)
{
struct mlxsw_sp_nexthop_group *nh_grp = fib_entry->nh_group;
int i;
if (fib_entry->type == MLXSW_SP_FIB_ENTRY_TYPE_LOCAL) {
nh_grp->nexthops->key.fib_nh->nh_flags |= RTNH_F_OFFLOAD;
return;
}
for (i = 0; i < nh_grp->count; i++) {
struct mlxsw_sp_nexthop *nh = &nh_grp->nexthops[i];
if (nh->offloaded)
nh->key.fib_nh->nh_flags |= RTNH_F_OFFLOAD;
else
nh->key.fib_nh->nh_flags &= ~RTNH_F_OFFLOAD;
}
}
static void
mlxsw_sp_fib4_entry_offload_unset(struct mlxsw_sp_fib_entry *fib_entry)
{ {
fib_entry->offloaded = true; struct mlxsw_sp_nexthop_group *nh_grp = fib_entry->nh_group;
int i;
for (i = 0; i < nh_grp->count; i++) {
struct mlxsw_sp_nexthop *nh = &nh_grp->nexthops[i];
nh->key.fib_nh->nh_flags &= ~RTNH_F_OFFLOAD;
}
}
static void mlxsw_sp_fib_entry_offload_set(struct mlxsw_sp_fib_entry *fib_entry)
{
switch (fib_entry->fib_node->fib->proto) { switch (fib_entry->fib_node->fib->proto) {
case MLXSW_SP_L3_PROTO_IPV4: case MLXSW_SP_L3_PROTO_IPV4:
fib_info_offload_inc(fib_entry->nh_group->key.fi); mlxsw_sp_fib4_entry_offload_set(fib_entry);
break; break;
case MLXSW_SP_L3_PROTO_IPV6: case MLXSW_SP_L3_PROTO_IPV6:
WARN_ON_ONCE(1); WARN_ON_ONCE(1);
...@@ -2121,13 +2174,11 @@ mlxsw_sp_fib_entry_offload_unset(struct mlxsw_sp_fib_entry *fib_entry) ...@@ -2121,13 +2174,11 @@ mlxsw_sp_fib_entry_offload_unset(struct mlxsw_sp_fib_entry *fib_entry)
{ {
switch (fib_entry->fib_node->fib->proto) { switch (fib_entry->fib_node->fib->proto) {
case MLXSW_SP_L3_PROTO_IPV4: case MLXSW_SP_L3_PROTO_IPV4:
fib_info_offload_dec(fib_entry->nh_group->key.fi); mlxsw_sp_fib4_entry_offload_unset(fib_entry);
break; break;
case MLXSW_SP_L3_PROTO_IPV6: case MLXSW_SP_L3_PROTO_IPV6:
WARN_ON_ONCE(1); WARN_ON_ONCE(1);
} }
fib_entry->offloaded = false;
} }
static void static void
...@@ -2136,17 +2187,13 @@ mlxsw_sp_fib_entry_offload_refresh(struct mlxsw_sp_fib_entry *fib_entry, ...@@ -2136,17 +2187,13 @@ mlxsw_sp_fib_entry_offload_refresh(struct mlxsw_sp_fib_entry *fib_entry,
{ {
switch (op) { switch (op) {
case MLXSW_REG_RALUE_OP_WRITE_DELETE: case MLXSW_REG_RALUE_OP_WRITE_DELETE:
if (!fib_entry->offloaded)
return;
return mlxsw_sp_fib_entry_offload_unset(fib_entry); return mlxsw_sp_fib_entry_offload_unset(fib_entry);
case MLXSW_REG_RALUE_OP_WRITE_WRITE: case MLXSW_REG_RALUE_OP_WRITE_WRITE:
if (err) if (err)
return; return;
if (mlxsw_sp_fib_entry_should_offload(fib_entry) && if (mlxsw_sp_fib_entry_should_offload(fib_entry))
!fib_entry->offloaded)
mlxsw_sp_fib_entry_offload_set(fib_entry); mlxsw_sp_fib_entry_offload_set(fib_entry);
else if (!mlxsw_sp_fib_entry_should_offload(fib_entry) && else if (!mlxsw_sp_fib_entry_should_offload(fib_entry))
fib_entry->offloaded)
mlxsw_sp_fib_entry_offload_unset(fib_entry); mlxsw_sp_fib_entry_offload_unset(fib_entry);
return; return;
default: default:
......
...@@ -2761,7 +2761,7 @@ static int ofdpa_fib4_add(struct rocker *rocker, ...@@ -2761,7 +2761,7 @@ static int ofdpa_fib4_add(struct rocker *rocker,
fen_info->tb_id, 0); fen_info->tb_id, 0);
if (err) if (err)
return err; return err;
fib_info_offload_inc(fen_info->fi); fen_info->fi->fib_nh->nh_flags |= RTNH_F_OFFLOAD;
return 0; return 0;
} }
...@@ -2776,7 +2776,7 @@ static int ofdpa_fib4_del(struct rocker *rocker, ...@@ -2776,7 +2776,7 @@ static int ofdpa_fib4_del(struct rocker *rocker,
ofdpa_port = ofdpa_port_dev_lower_find(fen_info->fi->fib_dev, rocker); ofdpa_port = ofdpa_port_dev_lower_find(fen_info->fi->fib_dev, rocker);
if (!ofdpa_port) if (!ofdpa_port)
return 0; return 0;
fib_info_offload_dec(fen_info->fi); fen_info->fi->fib_nh->nh_flags &= ~RTNH_F_OFFLOAD;
return ofdpa_port_fib_ipv4(ofdpa_port, htonl(fen_info->dst), return ofdpa_port_fib_ipv4(ofdpa_port, htonl(fen_info->dst),
fen_info->dst_len, fen_info->fi, fen_info->dst_len, fen_info->fi,
fen_info->tb_id, OFDPA_OP_FLAG_REMOVE); fen_info->tb_id, OFDPA_OP_FLAG_REMOVE);
...@@ -2803,7 +2803,7 @@ static void ofdpa_fib4_abort(struct rocker *rocker) ...@@ -2803,7 +2803,7 @@ static void ofdpa_fib4_abort(struct rocker *rocker)
rocker); rocker);
if (!ofdpa_port) if (!ofdpa_port)
continue; continue;
fib_info_offload_dec(flow_entry->fi); flow_entry->fi->fib_nh->nh_flags &= ~RTNH_F_OFFLOAD;
ofdpa_flow_tbl_del(ofdpa_port, OFDPA_OP_FLAG_REMOVE, ofdpa_flow_tbl_del(ofdpa_port, OFDPA_OP_FLAG_REMOVE,
flow_entry); flow_entry);
} }
......
...@@ -124,7 +124,6 @@ struct fib_info { ...@@ -124,7 +124,6 @@ struct fib_info {
#ifdef CONFIG_IP_ROUTE_MULTIPATH #ifdef CONFIG_IP_ROUTE_MULTIPATH
int fib_weight; int fib_weight;
#endif #endif
unsigned int fib_offload_cnt;
struct rcu_head rcu; struct rcu_head rcu;
struct fib_nh fib_nh[0]; struct fib_nh fib_nh[0];
#define fib_dev fib_nh[0].nh_dev #define fib_dev fib_nh[0].nh_dev
...@@ -177,18 +176,6 @@ struct fib_result_nl { ...@@ -177,18 +176,6 @@ struct fib_result_nl {
__be32 fib_info_update_nh_saddr(struct net *net, struct fib_nh *nh); __be32 fib_info_update_nh_saddr(struct net *net, struct fib_nh *nh);
static inline void fib_info_offload_inc(struct fib_info *fi)
{
fi->fib_offload_cnt++;
fi->fib_flags |= RTNH_F_OFFLOAD;
}
static inline void fib_info_offload_dec(struct fib_info *fi)
{
if (--fi->fib_offload_cnt == 0)
fi->fib_flags &= ~RTNH_F_OFFLOAD;
}
#define FIB_RES_SADDR(net, res) \ #define FIB_RES_SADDR(net, res) \
((FIB_RES_NH(res).nh_saddr_genid == \ ((FIB_RES_NH(res).nh_saddr_genid == \
atomic_read(&(net)->ipv4.dev_addr_genid)) ? \ atomic_read(&(net)->ipv4.dev_addr_genid)) ? \
......
...@@ -1342,6 +1342,8 @@ int fib_dump_info(struct sk_buff *skb, u32 portid, u32 seq, int event, ...@@ -1342,6 +1342,8 @@ int fib_dump_info(struct sk_buff *skb, u32 portid, u32 seq, int event,
IN_DEV_IGNORE_ROUTES_WITH_LINKDOWN(in_dev)) IN_DEV_IGNORE_ROUTES_WITH_LINKDOWN(in_dev))
rtm->rtm_flags |= RTNH_F_DEAD; rtm->rtm_flags |= RTNH_F_DEAD;
} }
if (fi->fib_nh->nh_flags & RTNH_F_OFFLOAD)
rtm->rtm_flags |= RTNH_F_OFFLOAD;
#ifdef CONFIG_IP_ROUTE_CLASSID #ifdef CONFIG_IP_ROUTE_CLASSID
if (fi->fib_nh[0].nh_tclassid && if (fi->fib_nh[0].nh_tclassid &&
nla_put_u32(skb, RTA_FLOW, fi->fib_nh[0].nh_tclassid)) nla_put_u32(skb, RTA_FLOW, fi->fib_nh[0].nh_tclassid))
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment