diff options
author | Jiri Pirko <jiri@mellanox.com> | 2016-04-14 12:19:14 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2016-04-14 16:22:03 -0400 |
commit | df38dafd255954ee7012785c62e615f595d5cb3c (patch) | |
tree | 493e781aa7b44ba00a23ea6162b04c93918d0732 | |
parent | bf7974710a40aaeb69dee7f62d91048bdaf79c76 (diff) |
devlink: implement shared buffer occupancy monitoring interface
User needs to monitor shared buffer occupancy. For that, he issues a
snapshot command in order to instruct hardware to catch current and
maximal occupancy values, and clear command in order to clear the
historical maximal values.
Also port-pool and tc-pool-bind command response messages are extended to
carry occupancy values.
Signed-off-by: Jiri Pirko <jiri@mellanox.com>
Reviewed-by: Ido Schimmel <idosch@mellanox.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r-- | include/net/devlink.h | 12 | ||||
-rw-r--r-- | include/uapi/linux/devlink.h | 6 | ||||
-rw-r--r-- | net/core/devlink.c | 98 |
3 files changed, 110 insertions, 6 deletions
diff --git a/include/net/devlink.h b/include/net/devlink.h index e4c27473ee4f..be64218e0254 100644 --- a/include/net/devlink.h +++ b/include/net/devlink.h | |||
@@ -78,6 +78,18 @@ struct devlink_ops { | |||
78 | u16 tc_index, | 78 | u16 tc_index, |
79 | enum devlink_sb_pool_type pool_type, | 79 | enum devlink_sb_pool_type pool_type, |
80 | u16 pool_index, u32 threshold); | 80 | u16 pool_index, u32 threshold); |
81 | int (*sb_occ_snapshot)(struct devlink *devlink, | ||
82 | unsigned int sb_index); | ||
83 | int (*sb_occ_max_clear)(struct devlink *devlink, | ||
84 | unsigned int sb_index); | ||
85 | int (*sb_occ_port_pool_get)(struct devlink_port *devlink_port, | ||
86 | unsigned int sb_index, u16 pool_index, | ||
87 | u32 *p_cur, u32 *p_max); | ||
88 | int (*sb_occ_tc_port_bind_get)(struct devlink_port *devlink_port, | ||
89 | unsigned int sb_index, | ||
90 | u16 tc_index, | ||
91 | enum devlink_sb_pool_type pool_type, | ||
92 | u32 *p_cur, u32 *p_max); | ||
81 | }; | 93 | }; |
82 | 94 | ||
83 | static inline void *devlink_priv(struct devlink *devlink) | 95 | static inline void *devlink_priv(struct devlink *devlink) |
diff --git a/include/uapi/linux/devlink.h b/include/uapi/linux/devlink.h index 9c1aa5783090..ba0073b26fa6 100644 --- a/include/uapi/linux/devlink.h +++ b/include/uapi/linux/devlink.h | |||
@@ -53,6 +53,10 @@ enum devlink_command { | |||
53 | DEVLINK_CMD_SB_TC_POOL_BIND_NEW, | 53 | DEVLINK_CMD_SB_TC_POOL_BIND_NEW, |
54 | DEVLINK_CMD_SB_TC_POOL_BIND_DEL, | 54 | DEVLINK_CMD_SB_TC_POOL_BIND_DEL, |
55 | 55 | ||
56 | /* Shared buffer occupancy monitoring commands */ | ||
57 | DEVLINK_CMD_SB_OCC_SNAPSHOT, | ||
58 | DEVLINK_CMD_SB_OCC_MAX_CLEAR, | ||
59 | |||
56 | /* add new commands above here */ | 60 | /* add new commands above here */ |
57 | 61 | ||
58 | __DEVLINK_CMD_MAX, | 62 | __DEVLINK_CMD_MAX, |
@@ -119,6 +123,8 @@ enum devlink_attr { | |||
119 | DEVLINK_ATTR_SB_POOL_THRESHOLD_TYPE, /* u8 */ | 123 | DEVLINK_ATTR_SB_POOL_THRESHOLD_TYPE, /* u8 */ |
120 | DEVLINK_ATTR_SB_THRESHOLD, /* u32 */ | 124 | DEVLINK_ATTR_SB_THRESHOLD, /* u32 */ |
121 | DEVLINK_ATTR_SB_TC_INDEX, /* u16 */ | 125 | DEVLINK_ATTR_SB_TC_INDEX, /* u16 */ |
126 | DEVLINK_ATTR_SB_OCC_CUR, /* u32 */ | ||
127 | DEVLINK_ATTR_SB_OCC_MAX, /* u32 */ | ||
122 | 128 | ||
123 | /* add new attributes above here, update the policy in devlink.c */ | 129 | /* add new attributes above here, update the policy in devlink.c */ |
124 | 130 | ||
diff --git a/net/core/devlink.c b/net/core/devlink.c index aa0b9e1542e7..933e8d4d3968 100644 --- a/net/core/devlink.c +++ b/net/core/devlink.c | |||
@@ -280,6 +280,10 @@ devlink_sb_tc_index_get_from_info(struct devlink_sb *devlink_sb, | |||
280 | #define DEVLINK_NL_FLAG_NEED_DEVLINK BIT(0) | 280 | #define DEVLINK_NL_FLAG_NEED_DEVLINK BIT(0) |
281 | #define DEVLINK_NL_FLAG_NEED_PORT BIT(1) | 281 | #define DEVLINK_NL_FLAG_NEED_PORT BIT(1) |
282 | #define DEVLINK_NL_FLAG_NEED_SB BIT(2) | 282 | #define DEVLINK_NL_FLAG_NEED_SB BIT(2) |
283 | #define DEVLINK_NL_FLAG_LOCK_PORTS BIT(3) | ||
284 | /* port is not needed but we need to ensure they don't | ||
285 | * change in the middle of command | ||
286 | */ | ||
283 | 287 | ||
284 | static int devlink_nl_pre_doit(const struct genl_ops *ops, | 288 | static int devlink_nl_pre_doit(const struct genl_ops *ops, |
285 | struct sk_buff *skb, struct genl_info *info) | 289 | struct sk_buff *skb, struct genl_info *info) |
@@ -306,6 +310,9 @@ static int devlink_nl_pre_doit(const struct genl_ops *ops, | |||
306 | } | 310 | } |
307 | info->user_ptr[0] = devlink_port; | 311 | info->user_ptr[0] = devlink_port; |
308 | } | 312 | } |
313 | if (ops->internal_flags & DEVLINK_NL_FLAG_LOCK_PORTS) { | ||
314 | mutex_lock(&devlink_port_mutex); | ||
315 | } | ||
309 | if (ops->internal_flags & DEVLINK_NL_FLAG_NEED_SB) { | 316 | if (ops->internal_flags & DEVLINK_NL_FLAG_NEED_SB) { |
310 | struct devlink_sb *devlink_sb; | 317 | struct devlink_sb *devlink_sb; |
311 | 318 | ||
@@ -324,7 +331,8 @@ static int devlink_nl_pre_doit(const struct genl_ops *ops, | |||
324 | static void devlink_nl_post_doit(const struct genl_ops *ops, | 331 | static void devlink_nl_post_doit(const struct genl_ops *ops, |
325 | struct sk_buff *skb, struct genl_info *info) | 332 | struct sk_buff *skb, struct genl_info *info) |
326 | { | 333 | { |
327 | if (ops->internal_flags & DEVLINK_NL_FLAG_NEED_PORT) | 334 | if (ops->internal_flags & DEVLINK_NL_FLAG_NEED_PORT || |
335 | ops->internal_flags & DEVLINK_NL_FLAG_LOCK_PORTS) | ||
328 | mutex_unlock(&devlink_port_mutex); | 336 | mutex_unlock(&devlink_port_mutex); |
329 | mutex_unlock(&devlink_mutex); | 337 | mutex_unlock(&devlink_mutex); |
330 | } | 338 | } |
@@ -942,12 +950,13 @@ static int devlink_nl_sb_port_pool_fill(struct sk_buff *msg, | |||
942 | enum devlink_command cmd, | 950 | enum devlink_command cmd, |
943 | u32 portid, u32 seq, int flags) | 951 | u32 portid, u32 seq, int flags) |
944 | { | 952 | { |
953 | const struct devlink_ops *ops = devlink->ops; | ||
945 | u32 threshold; | 954 | u32 threshold; |
946 | void *hdr; | 955 | void *hdr; |
947 | int err; | 956 | int err; |
948 | 957 | ||
949 | err = devlink->ops->sb_port_pool_get(devlink_port, devlink_sb->index, | 958 | err = ops->sb_port_pool_get(devlink_port, devlink_sb->index, |
950 | pool_index, &threshold); | 959 | pool_index, &threshold); |
951 | if (err) | 960 | if (err) |
952 | return err; | 961 | return err; |
953 | 962 | ||
@@ -966,6 +975,22 @@ static int devlink_nl_sb_port_pool_fill(struct sk_buff *msg, | |||
966 | if (nla_put_u32(msg, DEVLINK_ATTR_SB_THRESHOLD, threshold)) | 975 | if (nla_put_u32(msg, DEVLINK_ATTR_SB_THRESHOLD, threshold)) |
967 | goto nla_put_failure; | 976 | goto nla_put_failure; |
968 | 977 | ||
978 | if (ops->sb_occ_port_pool_get) { | ||
979 | u32 cur; | ||
980 | u32 max; | ||
981 | |||
982 | err = ops->sb_occ_port_pool_get(devlink_port, devlink_sb->index, | ||
983 | pool_index, &cur, &max); | ||
984 | if (err && err != -EOPNOTSUPP) | ||
985 | return err; | ||
986 | if (!err) { | ||
987 | if (nla_put_u32(msg, DEVLINK_ATTR_SB_OCC_CUR, cur)) | ||
988 | goto nla_put_failure; | ||
989 | if (nla_put_u32(msg, DEVLINK_ATTR_SB_OCC_MAX, max)) | ||
990 | goto nla_put_failure; | ||
991 | } | ||
992 | } | ||
993 | |||
969 | genlmsg_end(msg, hdr); | 994 | genlmsg_end(msg, hdr); |
970 | return 0; | 995 | return 0; |
971 | 996 | ||
@@ -1114,14 +1139,15 @@ devlink_nl_sb_tc_pool_bind_fill(struct sk_buff *msg, struct devlink *devlink, | |||
1114 | enum devlink_command cmd, | 1139 | enum devlink_command cmd, |
1115 | u32 portid, u32 seq, int flags) | 1140 | u32 portid, u32 seq, int flags) |
1116 | { | 1141 | { |
1142 | const struct devlink_ops *ops = devlink->ops; | ||
1117 | u16 pool_index; | 1143 | u16 pool_index; |
1118 | u32 threshold; | 1144 | u32 threshold; |
1119 | void *hdr; | 1145 | void *hdr; |
1120 | int err; | 1146 | int err; |
1121 | 1147 | ||
1122 | err = devlink->ops->sb_tc_pool_bind_get(devlink_port, devlink_sb->index, | 1148 | err = ops->sb_tc_pool_bind_get(devlink_port, devlink_sb->index, |
1123 | tc_index, pool_type, | 1149 | tc_index, pool_type, |
1124 | &pool_index, &threshold); | 1150 | &pool_index, &threshold); |
1125 | if (err) | 1151 | if (err) |
1126 | return err; | 1152 | return err; |
1127 | 1153 | ||
@@ -1144,6 +1170,24 @@ devlink_nl_sb_tc_pool_bind_fill(struct sk_buff *msg, struct devlink *devlink, | |||
1144 | if (nla_put_u32(msg, DEVLINK_ATTR_SB_THRESHOLD, threshold)) | 1170 | if (nla_put_u32(msg, DEVLINK_ATTR_SB_THRESHOLD, threshold)) |
1145 | goto nla_put_failure; | 1171 | goto nla_put_failure; |
1146 | 1172 | ||
1173 | if (ops->sb_occ_tc_port_bind_get) { | ||
1174 | u32 cur; | ||
1175 | u32 max; | ||
1176 | |||
1177 | err = ops->sb_occ_tc_port_bind_get(devlink_port, | ||
1178 | devlink_sb->index, | ||
1179 | tc_index, pool_type, | ||
1180 | &cur, &max); | ||
1181 | if (err && err != -EOPNOTSUPP) | ||
1182 | return err; | ||
1183 | if (!err) { | ||
1184 | if (nla_put_u32(msg, DEVLINK_ATTR_SB_OCC_CUR, cur)) | ||
1185 | goto nla_put_failure; | ||
1186 | if (nla_put_u32(msg, DEVLINK_ATTR_SB_OCC_MAX, max)) | ||
1187 | goto nla_put_failure; | ||
1188 | } | ||
1189 | } | ||
1190 | |||
1147 | genlmsg_end(msg, hdr); | 1191 | genlmsg_end(msg, hdr); |
1148 | return 0; | 1192 | return 0; |
1149 | 1193 | ||
@@ -1326,6 +1370,30 @@ static int devlink_nl_cmd_sb_tc_pool_bind_set_doit(struct sk_buff *skb, | |||
1326 | pool_index, threshold); | 1370 | pool_index, threshold); |
1327 | } | 1371 | } |
1328 | 1372 | ||
1373 | static int devlink_nl_cmd_sb_occ_snapshot_doit(struct sk_buff *skb, | ||
1374 | struct genl_info *info) | ||
1375 | { | ||
1376 | struct devlink *devlink = info->user_ptr[0]; | ||
1377 | struct devlink_sb *devlink_sb = info->user_ptr[1]; | ||
1378 | const struct devlink_ops *ops = devlink->ops; | ||
1379 | |||
1380 | if (ops && ops->sb_occ_snapshot) | ||
1381 | return ops->sb_occ_snapshot(devlink, devlink_sb->index); | ||
1382 | return -EOPNOTSUPP; | ||
1383 | } | ||
1384 | |||
1385 | static int devlink_nl_cmd_sb_occ_max_clear_doit(struct sk_buff *skb, | ||
1386 | struct genl_info *info) | ||
1387 | { | ||
1388 | struct devlink *devlink = info->user_ptr[0]; | ||
1389 | struct devlink_sb *devlink_sb = info->user_ptr[1]; | ||
1390 | const struct devlink_ops *ops = devlink->ops; | ||
1391 | |||
1392 | if (ops && ops->sb_occ_max_clear) | ||
1393 | return ops->sb_occ_max_clear(devlink, devlink_sb->index); | ||
1394 | return -EOPNOTSUPP; | ||
1395 | } | ||
1396 | |||
1329 | static const struct nla_policy devlink_nl_policy[DEVLINK_ATTR_MAX + 1] = { | 1397 | static const struct nla_policy devlink_nl_policy[DEVLINK_ATTR_MAX + 1] = { |
1330 | [DEVLINK_ATTR_BUS_NAME] = { .type = NLA_NUL_STRING }, | 1398 | [DEVLINK_ATTR_BUS_NAME] = { .type = NLA_NUL_STRING }, |
1331 | [DEVLINK_ATTR_DEV_NAME] = { .type = NLA_NUL_STRING }, | 1399 | [DEVLINK_ATTR_DEV_NAME] = { .type = NLA_NUL_STRING }, |
@@ -1439,6 +1507,24 @@ static const struct genl_ops devlink_nl_ops[] = { | |||
1439 | .internal_flags = DEVLINK_NL_FLAG_NEED_PORT | | 1507 | .internal_flags = DEVLINK_NL_FLAG_NEED_PORT | |
1440 | DEVLINK_NL_FLAG_NEED_SB, | 1508 | DEVLINK_NL_FLAG_NEED_SB, |
1441 | }, | 1509 | }, |
1510 | { | ||
1511 | .cmd = DEVLINK_CMD_SB_OCC_SNAPSHOT, | ||
1512 | .doit = devlink_nl_cmd_sb_occ_snapshot_doit, | ||
1513 | .policy = devlink_nl_policy, | ||
1514 | .flags = GENL_ADMIN_PERM, | ||
1515 | .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK | | ||
1516 | DEVLINK_NL_FLAG_NEED_SB | | ||
1517 | DEVLINK_NL_FLAG_LOCK_PORTS, | ||
1518 | }, | ||
1519 | { | ||
1520 | .cmd = DEVLINK_CMD_SB_OCC_MAX_CLEAR, | ||
1521 | .doit = devlink_nl_cmd_sb_occ_max_clear_doit, | ||
1522 | .policy = devlink_nl_policy, | ||
1523 | .flags = GENL_ADMIN_PERM, | ||
1524 | .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK | | ||
1525 | DEVLINK_NL_FLAG_NEED_SB | | ||
1526 | DEVLINK_NL_FLAG_LOCK_PORTS, | ||
1527 | }, | ||
1442 | }; | 1528 | }; |
1443 | 1529 | ||
1444 | /** | 1530 | /** |