diff options
author | Jiri Pirko <jiri@mellanox.com> | 2016-04-14 12:19:13 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2016-04-14 16:22:03 -0400 |
commit | bf7974710a40aaeb69dee7f62d91048bdaf79c76 (patch) | |
tree | adff44085782f226cbb473dae79bd04024b507b7 | |
parent | f38ba953bee01887d520f7abba536721a1d16477 (diff) |
devlink: add shared buffer configuration
Define userspace API and drivers API for configuration of shared
buffers. Four basic objects are defined:
shared buffer - attributes are size, number of pools and TCs
pool - chunk of sharedbuffer definition, it has some size and either
static or dynamic threshold
port pool threshold - to set per-port threshold for each pool
port tc threshold bind - to bind port and TC to specified pool
with threshold.
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 | 47 | ||||
-rw-r--r-- | include/uapi/linux/devlink.h | 57 | ||||
-rw-r--r-- | net/core/devlink.c | 940 |
3 files changed, 1044 insertions, 0 deletions
diff --git a/include/net/devlink.h b/include/net/devlink.h index c37d257891d6..e4c27473ee4f 100644 --- a/include/net/devlink.h +++ b/include/net/devlink.h | |||
@@ -24,6 +24,7 @@ struct devlink_ops; | |||
24 | struct devlink { | 24 | struct devlink { |
25 | struct list_head list; | 25 | struct list_head list; |
26 | struct list_head port_list; | 26 | struct list_head port_list; |
27 | struct list_head sb_list; | ||
27 | const struct devlink_ops *ops; | 28 | const struct devlink_ops *ops; |
28 | struct device *dev; | 29 | struct device *dev; |
29 | possible_net_t _net; | 30 | possible_net_t _net; |
@@ -42,6 +43,12 @@ struct devlink_port { | |||
42 | u32 split_group; | 43 | u32 split_group; |
43 | }; | 44 | }; |
44 | 45 | ||
46 | struct devlink_sb_pool_info { | ||
47 | enum devlink_sb_pool_type pool_type; | ||
48 | u32 size; | ||
49 | enum devlink_sb_threshold_type threshold_type; | ||
50 | }; | ||
51 | |||
45 | struct devlink_ops { | 52 | struct devlink_ops { |
46 | size_t priv_size; | 53 | size_t priv_size; |
47 | int (*port_type_set)(struct devlink_port *devlink_port, | 54 | int (*port_type_set)(struct devlink_port *devlink_port, |
@@ -49,6 +56,28 @@ struct devlink_ops { | |||
49 | int (*port_split)(struct devlink *devlink, unsigned int port_index, | 56 | int (*port_split)(struct devlink *devlink, unsigned int port_index, |
50 | unsigned int count); | 57 | unsigned int count); |
51 | int (*port_unsplit)(struct devlink *devlink, unsigned int port_index); | 58 | int (*port_unsplit)(struct devlink *devlink, unsigned int port_index); |
59 | int (*sb_pool_get)(struct devlink *devlink, unsigned int sb_index, | ||
60 | u16 pool_index, | ||
61 | struct devlink_sb_pool_info *pool_info); | ||
62 | int (*sb_pool_set)(struct devlink *devlink, unsigned int sb_index, | ||
63 | u16 pool_index, u32 size, | ||
64 | enum devlink_sb_threshold_type threshold_type); | ||
65 | int (*sb_port_pool_get)(struct devlink_port *devlink_port, | ||
66 | unsigned int sb_index, u16 pool_index, | ||
67 | u32 *p_threshold); | ||
68 | int (*sb_port_pool_set)(struct devlink_port *devlink_port, | ||
69 | unsigned int sb_index, u16 pool_index, | ||
70 | u32 threshold); | ||
71 | int (*sb_tc_pool_bind_get)(struct devlink_port *devlink_port, | ||
72 | unsigned int sb_index, | ||
73 | u16 tc_index, | ||
74 | enum devlink_sb_pool_type pool_type, | ||
75 | u16 *p_pool_index, u32 *p_threshold); | ||
76 | int (*sb_tc_pool_bind_set)(struct devlink_port *devlink_port, | ||
77 | unsigned int sb_index, | ||
78 | u16 tc_index, | ||
79 | enum devlink_sb_pool_type pool_type, | ||
80 | u16 pool_index, u32 threshold); | ||
52 | }; | 81 | }; |
53 | 82 | ||
54 | static inline void *devlink_priv(struct devlink *devlink) | 83 | static inline void *devlink_priv(struct devlink *devlink) |
@@ -82,6 +111,11 @@ void devlink_port_type_ib_set(struct devlink_port *devlink_port, | |||
82 | void devlink_port_type_clear(struct devlink_port *devlink_port); | 111 | void devlink_port_type_clear(struct devlink_port *devlink_port); |
83 | void devlink_port_split_set(struct devlink_port *devlink_port, | 112 | void devlink_port_split_set(struct devlink_port *devlink_port, |
84 | u32 split_group); | 113 | u32 split_group); |
114 | int devlink_sb_register(struct devlink *devlink, unsigned int sb_index, | ||
115 | u32 size, u16 ingress_pools_count, | ||
116 | u16 egress_pools_count, u16 ingress_tc_count, | ||
117 | u16 egress_tc_count); | ||
118 | void devlink_sb_unregister(struct devlink *devlink, unsigned int sb_index); | ||
85 | 119 | ||
86 | #else | 120 | #else |
87 | 121 | ||
@@ -135,6 +169,19 @@ static inline void devlink_port_split_set(struct devlink_port *devlink_port, | |||
135 | { | 169 | { |
136 | } | 170 | } |
137 | 171 | ||
172 | static inline int devlink_sb_register(struct devlink *devlink, | ||
173 | unsigned int sb_index, u32 size, | ||
174 | u16 ingress_pools_count, | ||
175 | u16 egress_pools_count, u16 tc_count) | ||
176 | { | ||
177 | return 0; | ||
178 | } | ||
179 | |||
180 | static inline void devlink_sb_unregister(struct devlink *devlink, | ||
181 | unsigned int sb_index) | ||
182 | { | ||
183 | } | ||
184 | |||
138 | #endif | 185 | #endif |
139 | 186 | ||
140 | #endif /* _NET_DEVLINK_H_ */ | 187 | #endif /* _NET_DEVLINK_H_ */ |
diff --git a/include/uapi/linux/devlink.h b/include/uapi/linux/devlink.h index c9fee5781eb1..9c1aa5783090 100644 --- a/include/uapi/linux/devlink.h +++ b/include/uapi/linux/devlink.h | |||
@@ -33,6 +33,26 @@ enum devlink_command { | |||
33 | DEVLINK_CMD_PORT_SPLIT, | 33 | DEVLINK_CMD_PORT_SPLIT, |
34 | DEVLINK_CMD_PORT_UNSPLIT, | 34 | DEVLINK_CMD_PORT_UNSPLIT, |
35 | 35 | ||
36 | DEVLINK_CMD_SB_GET, /* can dump */ | ||
37 | DEVLINK_CMD_SB_SET, | ||
38 | DEVLINK_CMD_SB_NEW, | ||
39 | DEVLINK_CMD_SB_DEL, | ||
40 | |||
41 | DEVLINK_CMD_SB_POOL_GET, /* can dump */ | ||
42 | DEVLINK_CMD_SB_POOL_SET, | ||
43 | DEVLINK_CMD_SB_POOL_NEW, | ||
44 | DEVLINK_CMD_SB_POOL_DEL, | ||
45 | |||
46 | DEVLINK_CMD_SB_PORT_POOL_GET, /* can dump */ | ||
47 | DEVLINK_CMD_SB_PORT_POOL_SET, | ||
48 | DEVLINK_CMD_SB_PORT_POOL_NEW, | ||
49 | DEVLINK_CMD_SB_PORT_POOL_DEL, | ||
50 | |||
51 | DEVLINK_CMD_SB_TC_POOL_BIND_GET, /* can dump */ | ||
52 | DEVLINK_CMD_SB_TC_POOL_BIND_SET, | ||
53 | DEVLINK_CMD_SB_TC_POOL_BIND_NEW, | ||
54 | DEVLINK_CMD_SB_TC_POOL_BIND_DEL, | ||
55 | |||
36 | /* add new commands above here */ | 56 | /* add new commands above here */ |
37 | 57 | ||
38 | __DEVLINK_CMD_MAX, | 58 | __DEVLINK_CMD_MAX, |
@@ -46,6 +66,31 @@ enum devlink_port_type { | |||
46 | DEVLINK_PORT_TYPE_IB, | 66 | DEVLINK_PORT_TYPE_IB, |
47 | }; | 67 | }; |
48 | 68 | ||
69 | enum devlink_sb_pool_type { | ||
70 | DEVLINK_SB_POOL_TYPE_INGRESS, | ||
71 | DEVLINK_SB_POOL_TYPE_EGRESS, | ||
72 | }; | ||
73 | |||
74 | /* static threshold - limiting the maximum number of bytes. | ||
75 | * dynamic threshold - limiting the maximum number of bytes | ||
76 | * based on the currently available free space in the shared buffer pool. | ||
77 | * In this mode, the maximum quota is calculated based | ||
78 | * on the following formula: | ||
79 | * max_quota = alpha / (1 + alpha) * Free_Buffer | ||
80 | * While Free_Buffer is the amount of none-occupied buffer associated to | ||
81 | * the relevant pool. | ||
82 | * The value range which can be passed is 0-20 and serves | ||
83 | * for computation of alpha by following formula: | ||
84 | * alpha = 2 ^ (passed_value - 10) | ||
85 | */ | ||
86 | |||
87 | enum devlink_sb_threshold_type { | ||
88 | DEVLINK_SB_THRESHOLD_TYPE_STATIC, | ||
89 | DEVLINK_SB_THRESHOLD_TYPE_DYNAMIC, | ||
90 | }; | ||
91 | |||
92 | #define DEVLINK_SB_THRESHOLD_TO_ALPHA_MAX 20 | ||
93 | |||
49 | enum devlink_attr { | 94 | enum devlink_attr { |
50 | /* don't change the order or add anything between, this is ABI! */ | 95 | /* don't change the order or add anything between, this is ABI! */ |
51 | DEVLINK_ATTR_UNSPEC, | 96 | DEVLINK_ATTR_UNSPEC, |
@@ -62,6 +107,18 @@ enum devlink_attr { | |||
62 | DEVLINK_ATTR_PORT_IBDEV_NAME, /* string */ | 107 | DEVLINK_ATTR_PORT_IBDEV_NAME, /* string */ |
63 | DEVLINK_ATTR_PORT_SPLIT_COUNT, /* u32 */ | 108 | DEVLINK_ATTR_PORT_SPLIT_COUNT, /* u32 */ |
64 | DEVLINK_ATTR_PORT_SPLIT_GROUP, /* u32 */ | 109 | DEVLINK_ATTR_PORT_SPLIT_GROUP, /* u32 */ |
110 | DEVLINK_ATTR_SB_INDEX, /* u32 */ | ||
111 | DEVLINK_ATTR_SB_SIZE, /* u32 */ | ||
112 | DEVLINK_ATTR_SB_INGRESS_POOL_COUNT, /* u16 */ | ||
113 | DEVLINK_ATTR_SB_EGRESS_POOL_COUNT, /* u16 */ | ||
114 | DEVLINK_ATTR_SB_INGRESS_TC_COUNT, /* u16 */ | ||
115 | DEVLINK_ATTR_SB_EGRESS_TC_COUNT, /* u16 */ | ||
116 | DEVLINK_ATTR_SB_POOL_INDEX, /* u16 */ | ||
117 | DEVLINK_ATTR_SB_POOL_TYPE, /* u8 */ | ||
118 | DEVLINK_ATTR_SB_POOL_SIZE, /* u32 */ | ||
119 | DEVLINK_ATTR_SB_POOL_THRESHOLD_TYPE, /* u8 */ | ||
120 | DEVLINK_ATTR_SB_THRESHOLD, /* u32 */ | ||
121 | DEVLINK_ATTR_SB_TC_INDEX, /* u16 */ | ||
65 | 122 | ||
66 | /* add new attributes above here, update the policy in devlink.c */ | 123 | /* add new attributes above here, update the policy in devlink.c */ |
67 | 124 | ||
diff --git a/net/core/devlink.c b/net/core/devlink.c index b84cf0df4a0e..aa0b9e1542e7 100644 --- a/net/core/devlink.c +++ b/net/core/devlink.c | |||
@@ -119,8 +119,167 @@ static struct devlink_port *devlink_port_get_from_info(struct devlink *devlink, | |||
119 | return devlink_port_get_from_attrs(devlink, info->attrs); | 119 | return devlink_port_get_from_attrs(devlink, info->attrs); |
120 | } | 120 | } |
121 | 121 | ||
122 | struct devlink_sb { | ||
123 | struct list_head list; | ||
124 | unsigned int index; | ||
125 | u32 size; | ||
126 | u16 ingress_pools_count; | ||
127 | u16 egress_pools_count; | ||
128 | u16 ingress_tc_count; | ||
129 | u16 egress_tc_count; | ||
130 | }; | ||
131 | |||
132 | static u16 devlink_sb_pool_count(struct devlink_sb *devlink_sb) | ||
133 | { | ||
134 | return devlink_sb->ingress_pools_count + devlink_sb->egress_pools_count; | ||
135 | } | ||
136 | |||
137 | static struct devlink_sb *devlink_sb_get_by_index(struct devlink *devlink, | ||
138 | unsigned int sb_index) | ||
139 | { | ||
140 | struct devlink_sb *devlink_sb; | ||
141 | |||
142 | list_for_each_entry(devlink_sb, &devlink->sb_list, list) { | ||
143 | if (devlink_sb->index == sb_index) | ||
144 | return devlink_sb; | ||
145 | } | ||
146 | return NULL; | ||
147 | } | ||
148 | |||
149 | static bool devlink_sb_index_exists(struct devlink *devlink, | ||
150 | unsigned int sb_index) | ||
151 | { | ||
152 | return devlink_sb_get_by_index(devlink, sb_index); | ||
153 | } | ||
154 | |||
155 | static struct devlink_sb *devlink_sb_get_from_attrs(struct devlink *devlink, | ||
156 | struct nlattr **attrs) | ||
157 | { | ||
158 | if (attrs[DEVLINK_ATTR_SB_INDEX]) { | ||
159 | u32 sb_index = nla_get_u32(attrs[DEVLINK_ATTR_SB_INDEX]); | ||
160 | struct devlink_sb *devlink_sb; | ||
161 | |||
162 | devlink_sb = devlink_sb_get_by_index(devlink, sb_index); | ||
163 | if (!devlink_sb) | ||
164 | return ERR_PTR(-ENODEV); | ||
165 | return devlink_sb; | ||
166 | } | ||
167 | return ERR_PTR(-EINVAL); | ||
168 | } | ||
169 | |||
170 | static struct devlink_sb *devlink_sb_get_from_info(struct devlink *devlink, | ||
171 | struct genl_info *info) | ||
172 | { | ||
173 | return devlink_sb_get_from_attrs(devlink, info->attrs); | ||
174 | } | ||
175 | |||
176 | static int devlink_sb_pool_index_get_from_attrs(struct devlink_sb *devlink_sb, | ||
177 | struct nlattr **attrs, | ||
178 | u16 *p_pool_index) | ||
179 | { | ||
180 | u16 val; | ||
181 | |||
182 | if (!attrs[DEVLINK_ATTR_SB_POOL_INDEX]) | ||
183 | return -EINVAL; | ||
184 | |||
185 | val = nla_get_u16(attrs[DEVLINK_ATTR_SB_POOL_INDEX]); | ||
186 | if (val >= devlink_sb_pool_count(devlink_sb)) | ||
187 | return -EINVAL; | ||
188 | *p_pool_index = val; | ||
189 | return 0; | ||
190 | } | ||
191 | |||
192 | static int devlink_sb_pool_index_get_from_info(struct devlink_sb *devlink_sb, | ||
193 | struct genl_info *info, | ||
194 | u16 *p_pool_index) | ||
195 | { | ||
196 | return devlink_sb_pool_index_get_from_attrs(devlink_sb, info->attrs, | ||
197 | p_pool_index); | ||
198 | } | ||
199 | |||
200 | static int | ||
201 | devlink_sb_pool_type_get_from_attrs(struct nlattr **attrs, | ||
202 | enum devlink_sb_pool_type *p_pool_type) | ||
203 | { | ||
204 | u8 val; | ||
205 | |||
206 | if (!attrs[DEVLINK_ATTR_SB_POOL_TYPE]) | ||
207 | return -EINVAL; | ||
208 | |||
209 | val = nla_get_u8(attrs[DEVLINK_ATTR_SB_POOL_TYPE]); | ||
210 | if (val != DEVLINK_SB_POOL_TYPE_INGRESS && | ||
211 | val != DEVLINK_SB_POOL_TYPE_EGRESS) | ||
212 | return -EINVAL; | ||
213 | *p_pool_type = val; | ||
214 | return 0; | ||
215 | } | ||
216 | |||
217 | static int | ||
218 | devlink_sb_pool_type_get_from_info(struct genl_info *info, | ||
219 | enum devlink_sb_pool_type *p_pool_type) | ||
220 | { | ||
221 | return devlink_sb_pool_type_get_from_attrs(info->attrs, p_pool_type); | ||
222 | } | ||
223 | |||
224 | static int | ||
225 | devlink_sb_th_type_get_from_attrs(struct nlattr **attrs, | ||
226 | enum devlink_sb_threshold_type *p_th_type) | ||
227 | { | ||
228 | u8 val; | ||
229 | |||
230 | if (!attrs[DEVLINK_ATTR_SB_POOL_THRESHOLD_TYPE]) | ||
231 | return -EINVAL; | ||
232 | |||
233 | val = nla_get_u8(attrs[DEVLINK_ATTR_SB_POOL_THRESHOLD_TYPE]); | ||
234 | if (val != DEVLINK_SB_THRESHOLD_TYPE_STATIC && | ||
235 | val != DEVLINK_SB_THRESHOLD_TYPE_DYNAMIC) | ||
236 | return -EINVAL; | ||
237 | *p_th_type = val; | ||
238 | return 0; | ||
239 | } | ||
240 | |||
241 | static int | ||
242 | devlink_sb_th_type_get_from_info(struct genl_info *info, | ||
243 | enum devlink_sb_threshold_type *p_th_type) | ||
244 | { | ||
245 | return devlink_sb_th_type_get_from_attrs(info->attrs, p_th_type); | ||
246 | } | ||
247 | |||
248 | static int | ||
249 | devlink_sb_tc_index_get_from_attrs(struct devlink_sb *devlink_sb, | ||
250 | struct nlattr **attrs, | ||
251 | enum devlink_sb_pool_type pool_type, | ||
252 | u16 *p_tc_index) | ||
253 | { | ||
254 | u16 val; | ||
255 | |||
256 | if (!attrs[DEVLINK_ATTR_SB_TC_INDEX]) | ||
257 | return -EINVAL; | ||
258 | |||
259 | val = nla_get_u16(attrs[DEVLINK_ATTR_SB_TC_INDEX]); | ||
260 | if (pool_type == DEVLINK_SB_POOL_TYPE_INGRESS && | ||
261 | val >= devlink_sb->ingress_tc_count) | ||
262 | return -EINVAL; | ||
263 | if (pool_type == DEVLINK_SB_POOL_TYPE_EGRESS && | ||
264 | val >= devlink_sb->egress_tc_count) | ||
265 | return -EINVAL; | ||
266 | *p_tc_index = val; | ||
267 | return 0; | ||
268 | } | ||
269 | |||
270 | static int | ||
271 | devlink_sb_tc_index_get_from_info(struct devlink_sb *devlink_sb, | ||
272 | struct genl_info *info, | ||
273 | enum devlink_sb_pool_type pool_type, | ||
274 | u16 *p_tc_index) | ||
275 | { | ||
276 | return devlink_sb_tc_index_get_from_attrs(devlink_sb, info->attrs, | ||
277 | pool_type, p_tc_index); | ||
278 | } | ||
279 | |||
122 | #define DEVLINK_NL_FLAG_NEED_DEVLINK BIT(0) | 280 | #define DEVLINK_NL_FLAG_NEED_DEVLINK BIT(0) |
123 | #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) | ||
124 | 283 | ||
125 | static int devlink_nl_pre_doit(const struct genl_ops *ops, | 284 | static int devlink_nl_pre_doit(const struct genl_ops *ops, |
126 | struct sk_buff *skb, struct genl_info *info) | 285 | struct sk_buff *skb, struct genl_info *info) |
@@ -147,6 +306,18 @@ static int devlink_nl_pre_doit(const struct genl_ops *ops, | |||
147 | } | 306 | } |
148 | info->user_ptr[0] = devlink_port; | 307 | info->user_ptr[0] = devlink_port; |
149 | } | 308 | } |
309 | if (ops->internal_flags & DEVLINK_NL_FLAG_NEED_SB) { | ||
310 | struct devlink_sb *devlink_sb; | ||
311 | |||
312 | devlink_sb = devlink_sb_get_from_info(devlink, info); | ||
313 | if (IS_ERR(devlink_sb)) { | ||
314 | if (ops->internal_flags & DEVLINK_NL_FLAG_NEED_PORT) | ||
315 | mutex_unlock(&devlink_port_mutex); | ||
316 | mutex_unlock(&devlink_mutex); | ||
317 | return PTR_ERR(devlink_sb); | ||
318 | } | ||
319 | info->user_ptr[1] = devlink_sb; | ||
320 | } | ||
150 | return 0; | 321 | return 0; |
151 | } | 322 | } |
152 | 323 | ||
@@ -499,12 +670,675 @@ static int devlink_nl_cmd_port_unsplit_doit(struct sk_buff *skb, | |||
499 | return devlink_port_unsplit(devlink, port_index); | 670 | return devlink_port_unsplit(devlink, port_index); |
500 | } | 671 | } |
501 | 672 | ||
673 | static int devlink_nl_sb_fill(struct sk_buff *msg, struct devlink *devlink, | ||
674 | struct devlink_sb *devlink_sb, | ||
675 | enum devlink_command cmd, u32 portid, | ||
676 | u32 seq, int flags) | ||
677 | { | ||
678 | void *hdr; | ||
679 | |||
680 | hdr = genlmsg_put(msg, portid, seq, &devlink_nl_family, flags, cmd); | ||
681 | if (!hdr) | ||
682 | return -EMSGSIZE; | ||
683 | |||
684 | if (devlink_nl_put_handle(msg, devlink)) | ||
685 | goto nla_put_failure; | ||
686 | if (nla_put_u32(msg, DEVLINK_ATTR_SB_INDEX, devlink_sb->index)) | ||
687 | goto nla_put_failure; | ||
688 | if (nla_put_u32(msg, DEVLINK_ATTR_SB_SIZE, devlink_sb->size)) | ||
689 | goto nla_put_failure; | ||
690 | if (nla_put_u16(msg, DEVLINK_ATTR_SB_INGRESS_POOL_COUNT, | ||
691 | devlink_sb->ingress_pools_count)) | ||
692 | goto nla_put_failure; | ||
693 | if (nla_put_u16(msg, DEVLINK_ATTR_SB_EGRESS_POOL_COUNT, | ||
694 | devlink_sb->egress_pools_count)) | ||
695 | goto nla_put_failure; | ||
696 | if (nla_put_u16(msg, DEVLINK_ATTR_SB_INGRESS_TC_COUNT, | ||
697 | devlink_sb->ingress_tc_count)) | ||
698 | goto nla_put_failure; | ||
699 | if (nla_put_u16(msg, DEVLINK_ATTR_SB_EGRESS_TC_COUNT, | ||
700 | devlink_sb->egress_tc_count)) | ||
701 | goto nla_put_failure; | ||
702 | |||
703 | genlmsg_end(msg, hdr); | ||
704 | return 0; | ||
705 | |||
706 | nla_put_failure: | ||
707 | genlmsg_cancel(msg, hdr); | ||
708 | return -EMSGSIZE; | ||
709 | } | ||
710 | |||
711 | static int devlink_nl_cmd_sb_get_doit(struct sk_buff *skb, | ||
712 | struct genl_info *info) | ||
713 | { | ||
714 | struct devlink *devlink = info->user_ptr[0]; | ||
715 | struct devlink_sb *devlink_sb = info->user_ptr[1]; | ||
716 | struct sk_buff *msg; | ||
717 | int err; | ||
718 | |||
719 | msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); | ||
720 | if (!msg) | ||
721 | return -ENOMEM; | ||
722 | |||
723 | err = devlink_nl_sb_fill(msg, devlink, devlink_sb, | ||
724 | DEVLINK_CMD_SB_NEW, | ||
725 | info->snd_portid, info->snd_seq, 0); | ||
726 | if (err) { | ||
727 | nlmsg_free(msg); | ||
728 | return err; | ||
729 | } | ||
730 | |||
731 | return genlmsg_reply(msg, info); | ||
732 | } | ||
733 | |||
734 | static int devlink_nl_cmd_sb_get_dumpit(struct sk_buff *msg, | ||
735 | struct netlink_callback *cb) | ||
736 | { | ||
737 | struct devlink *devlink; | ||
738 | struct devlink_sb *devlink_sb; | ||
739 | int start = cb->args[0]; | ||
740 | int idx = 0; | ||
741 | int err; | ||
742 | |||
743 | mutex_lock(&devlink_mutex); | ||
744 | list_for_each_entry(devlink, &devlink_list, list) { | ||
745 | if (!net_eq(devlink_net(devlink), sock_net(msg->sk))) | ||
746 | continue; | ||
747 | list_for_each_entry(devlink_sb, &devlink->sb_list, list) { | ||
748 | if (idx < start) { | ||
749 | idx++; | ||
750 | continue; | ||
751 | } | ||
752 | err = devlink_nl_sb_fill(msg, devlink, devlink_sb, | ||
753 | DEVLINK_CMD_SB_NEW, | ||
754 | NETLINK_CB(cb->skb).portid, | ||
755 | cb->nlh->nlmsg_seq, | ||
756 | NLM_F_MULTI); | ||
757 | if (err) | ||
758 | goto out; | ||
759 | idx++; | ||
760 | } | ||
761 | } | ||
762 | out: | ||
763 | mutex_unlock(&devlink_mutex); | ||
764 | |||
765 | cb->args[0] = idx; | ||
766 | return msg->len; | ||
767 | } | ||
768 | |||
769 | static int devlink_nl_sb_pool_fill(struct sk_buff *msg, struct devlink *devlink, | ||
770 | struct devlink_sb *devlink_sb, | ||
771 | u16 pool_index, enum devlink_command cmd, | ||
772 | u32 portid, u32 seq, int flags) | ||
773 | { | ||
774 | struct devlink_sb_pool_info pool_info; | ||
775 | void *hdr; | ||
776 | int err; | ||
777 | |||
778 | err = devlink->ops->sb_pool_get(devlink, devlink_sb->index, | ||
779 | pool_index, &pool_info); | ||
780 | if (err) | ||
781 | return err; | ||
782 | |||
783 | hdr = genlmsg_put(msg, portid, seq, &devlink_nl_family, flags, cmd); | ||
784 | if (!hdr) | ||
785 | return -EMSGSIZE; | ||
786 | |||
787 | if (devlink_nl_put_handle(msg, devlink)) | ||
788 | goto nla_put_failure; | ||
789 | if (nla_put_u32(msg, DEVLINK_ATTR_SB_INDEX, devlink_sb->index)) | ||
790 | goto nla_put_failure; | ||
791 | if (nla_put_u16(msg, DEVLINK_ATTR_SB_POOL_INDEX, pool_index)) | ||
792 | goto nla_put_failure; | ||
793 | if (nla_put_u8(msg, DEVLINK_ATTR_SB_POOL_TYPE, pool_info.pool_type)) | ||
794 | goto nla_put_failure; | ||
795 | if (nla_put_u32(msg, DEVLINK_ATTR_SB_POOL_SIZE, pool_info.size)) | ||
796 | goto nla_put_failure; | ||
797 | if (nla_put_u8(msg, DEVLINK_ATTR_SB_POOL_THRESHOLD_TYPE, | ||
798 | pool_info.threshold_type)) | ||
799 | goto nla_put_failure; | ||
800 | |||
801 | genlmsg_end(msg, hdr); | ||
802 | return 0; | ||
803 | |||
804 | nla_put_failure: | ||
805 | genlmsg_cancel(msg, hdr); | ||
806 | return -EMSGSIZE; | ||
807 | } | ||
808 | |||
809 | static int devlink_nl_cmd_sb_pool_get_doit(struct sk_buff *skb, | ||
810 | struct genl_info *info) | ||
811 | { | ||
812 | struct devlink *devlink = info->user_ptr[0]; | ||
813 | struct devlink_sb *devlink_sb = info->user_ptr[1]; | ||
814 | struct sk_buff *msg; | ||
815 | u16 pool_index; | ||
816 | int err; | ||
817 | |||
818 | err = devlink_sb_pool_index_get_from_info(devlink_sb, info, | ||
819 | &pool_index); | ||
820 | if (err) | ||
821 | return err; | ||
822 | |||
823 | if (!devlink->ops || !devlink->ops->sb_pool_get) | ||
824 | return -EOPNOTSUPP; | ||
825 | |||
826 | msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); | ||
827 | if (!msg) | ||
828 | return -ENOMEM; | ||
829 | |||
830 | err = devlink_nl_sb_pool_fill(msg, devlink, devlink_sb, pool_index, | ||
831 | DEVLINK_CMD_SB_POOL_NEW, | ||
832 | info->snd_portid, info->snd_seq, 0); | ||
833 | if (err) { | ||
834 | nlmsg_free(msg); | ||
835 | return err; | ||
836 | } | ||
837 | |||
838 | return genlmsg_reply(msg, info); | ||
839 | } | ||
840 | |||
841 | static int __sb_pool_get_dumpit(struct sk_buff *msg, int start, int *p_idx, | ||
842 | struct devlink *devlink, | ||
843 | struct devlink_sb *devlink_sb, | ||
844 | u32 portid, u32 seq) | ||
845 | { | ||
846 | u16 pool_count = devlink_sb_pool_count(devlink_sb); | ||
847 | u16 pool_index; | ||
848 | int err; | ||
849 | |||
850 | for (pool_index = 0; pool_index < pool_count; pool_index++) { | ||
851 | if (*p_idx < start) { | ||
852 | (*p_idx)++; | ||
853 | continue; | ||
854 | } | ||
855 | err = devlink_nl_sb_pool_fill(msg, devlink, | ||
856 | devlink_sb, | ||
857 | pool_index, | ||
858 | DEVLINK_CMD_SB_POOL_NEW, | ||
859 | portid, seq, NLM_F_MULTI); | ||
860 | if (err) | ||
861 | return err; | ||
862 | (*p_idx)++; | ||
863 | } | ||
864 | return 0; | ||
865 | } | ||
866 | |||
867 | static int devlink_nl_cmd_sb_pool_get_dumpit(struct sk_buff *msg, | ||
868 | struct netlink_callback *cb) | ||
869 | { | ||
870 | struct devlink *devlink; | ||
871 | struct devlink_sb *devlink_sb; | ||
872 | int start = cb->args[0]; | ||
873 | int idx = 0; | ||
874 | int err; | ||
875 | |||
876 | mutex_lock(&devlink_mutex); | ||
877 | list_for_each_entry(devlink, &devlink_list, list) { | ||
878 | if (!net_eq(devlink_net(devlink), sock_net(msg->sk)) || | ||
879 | !devlink->ops || !devlink->ops->sb_pool_get) | ||
880 | continue; | ||
881 | list_for_each_entry(devlink_sb, &devlink->sb_list, list) { | ||
882 | err = __sb_pool_get_dumpit(msg, start, &idx, devlink, | ||
883 | devlink_sb, | ||
884 | NETLINK_CB(cb->skb).portid, | ||
885 | cb->nlh->nlmsg_seq); | ||
886 | if (err && err != -EOPNOTSUPP) | ||
887 | goto out; | ||
888 | } | ||
889 | } | ||
890 | out: | ||
891 | mutex_unlock(&devlink_mutex); | ||
892 | |||
893 | cb->args[0] = idx; | ||
894 | return msg->len; | ||
895 | } | ||
896 | |||
897 | static int devlink_sb_pool_set(struct devlink *devlink, unsigned int sb_index, | ||
898 | u16 pool_index, u32 size, | ||
899 | enum devlink_sb_threshold_type threshold_type) | ||
900 | |||
901 | { | ||
902 | const struct devlink_ops *ops = devlink->ops; | ||
903 | |||
904 | if (ops && ops->sb_pool_set) | ||
905 | return ops->sb_pool_set(devlink, sb_index, pool_index, | ||
906 | size, threshold_type); | ||
907 | return -EOPNOTSUPP; | ||
908 | } | ||
909 | |||
910 | static int devlink_nl_cmd_sb_pool_set_doit(struct sk_buff *skb, | ||
911 | struct genl_info *info) | ||
912 | { | ||
913 | struct devlink *devlink = info->user_ptr[0]; | ||
914 | struct devlink_sb *devlink_sb = info->user_ptr[1]; | ||
915 | enum devlink_sb_threshold_type threshold_type; | ||
916 | u16 pool_index; | ||
917 | u32 size; | ||
918 | int err; | ||
919 | |||
920 | err = devlink_sb_pool_index_get_from_info(devlink_sb, info, | ||
921 | &pool_index); | ||
922 | if (err) | ||
923 | return err; | ||
924 | |||
925 | err = devlink_sb_th_type_get_from_info(info, &threshold_type); | ||
926 | if (err) | ||
927 | return err; | ||
928 | |||
929 | if (!info->attrs[DEVLINK_ATTR_SB_POOL_SIZE]) | ||
930 | return -EINVAL; | ||
931 | |||
932 | size = nla_get_u32(info->attrs[DEVLINK_ATTR_SB_POOL_SIZE]); | ||
933 | return devlink_sb_pool_set(devlink, devlink_sb->index, | ||
934 | pool_index, size, threshold_type); | ||
935 | } | ||
936 | |||
937 | static int devlink_nl_sb_port_pool_fill(struct sk_buff *msg, | ||
938 | struct devlink *devlink, | ||
939 | struct devlink_port *devlink_port, | ||
940 | struct devlink_sb *devlink_sb, | ||
941 | u16 pool_index, | ||
942 | enum devlink_command cmd, | ||
943 | u32 portid, u32 seq, int flags) | ||
944 | { | ||
945 | u32 threshold; | ||
946 | void *hdr; | ||
947 | int err; | ||
948 | |||
949 | err = devlink->ops->sb_port_pool_get(devlink_port, devlink_sb->index, | ||
950 | pool_index, &threshold); | ||
951 | if (err) | ||
952 | return err; | ||
953 | |||
954 | hdr = genlmsg_put(msg, portid, seq, &devlink_nl_family, flags, cmd); | ||
955 | if (!hdr) | ||
956 | return -EMSGSIZE; | ||
957 | |||
958 | if (devlink_nl_put_handle(msg, devlink)) | ||
959 | goto nla_put_failure; | ||
960 | if (nla_put_u32(msg, DEVLINK_ATTR_PORT_INDEX, devlink_port->index)) | ||
961 | goto nla_put_failure; | ||
962 | if (nla_put_u32(msg, DEVLINK_ATTR_SB_INDEX, devlink_sb->index)) | ||
963 | goto nla_put_failure; | ||
964 | if (nla_put_u16(msg, DEVLINK_ATTR_SB_POOL_INDEX, pool_index)) | ||
965 | goto nla_put_failure; | ||
966 | if (nla_put_u32(msg, DEVLINK_ATTR_SB_THRESHOLD, threshold)) | ||
967 | goto nla_put_failure; | ||
968 | |||
969 | genlmsg_end(msg, hdr); | ||
970 | return 0; | ||
971 | |||
972 | nla_put_failure: | ||
973 | genlmsg_cancel(msg, hdr); | ||
974 | return -EMSGSIZE; | ||
975 | } | ||
976 | |||
977 | static int devlink_nl_cmd_sb_port_pool_get_doit(struct sk_buff *skb, | ||
978 | struct genl_info *info) | ||
979 | { | ||
980 | struct devlink_port *devlink_port = info->user_ptr[0]; | ||
981 | struct devlink *devlink = devlink_port->devlink; | ||
982 | struct devlink_sb *devlink_sb = info->user_ptr[1]; | ||
983 | struct sk_buff *msg; | ||
984 | u16 pool_index; | ||
985 | int err; | ||
986 | |||
987 | err = devlink_sb_pool_index_get_from_info(devlink_sb, info, | ||
988 | &pool_index); | ||
989 | if (err) | ||
990 | return err; | ||
991 | |||
992 | if (!devlink->ops || !devlink->ops->sb_port_pool_get) | ||
993 | return -EOPNOTSUPP; | ||
994 | |||
995 | msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); | ||
996 | if (!msg) | ||
997 | return -ENOMEM; | ||
998 | |||
999 | err = devlink_nl_sb_port_pool_fill(msg, devlink, devlink_port, | ||
1000 | devlink_sb, pool_index, | ||
1001 | DEVLINK_CMD_SB_PORT_POOL_NEW, | ||
1002 | info->snd_portid, info->snd_seq, 0); | ||
1003 | if (err) { | ||
1004 | nlmsg_free(msg); | ||
1005 | return err; | ||
1006 | } | ||
1007 | |||
1008 | return genlmsg_reply(msg, info); | ||
1009 | } | ||
1010 | |||
1011 | static int __sb_port_pool_get_dumpit(struct sk_buff *msg, int start, int *p_idx, | ||
1012 | struct devlink *devlink, | ||
1013 | struct devlink_sb *devlink_sb, | ||
1014 | u32 portid, u32 seq) | ||
1015 | { | ||
1016 | struct devlink_port *devlink_port; | ||
1017 | u16 pool_count = devlink_sb_pool_count(devlink_sb); | ||
1018 | u16 pool_index; | ||
1019 | int err; | ||
1020 | |||
1021 | list_for_each_entry(devlink_port, &devlink->port_list, list) { | ||
1022 | for (pool_index = 0; pool_index < pool_count; pool_index++) { | ||
1023 | if (*p_idx < start) { | ||
1024 | (*p_idx)++; | ||
1025 | continue; | ||
1026 | } | ||
1027 | err = devlink_nl_sb_port_pool_fill(msg, devlink, | ||
1028 | devlink_port, | ||
1029 | devlink_sb, | ||
1030 | pool_index, | ||
1031 | DEVLINK_CMD_SB_PORT_POOL_NEW, | ||
1032 | portid, seq, | ||
1033 | NLM_F_MULTI); | ||
1034 | if (err) | ||
1035 | return err; | ||
1036 | (*p_idx)++; | ||
1037 | } | ||
1038 | } | ||
1039 | return 0; | ||
1040 | } | ||
1041 | |||
1042 | static int devlink_nl_cmd_sb_port_pool_get_dumpit(struct sk_buff *msg, | ||
1043 | struct netlink_callback *cb) | ||
1044 | { | ||
1045 | struct devlink *devlink; | ||
1046 | struct devlink_sb *devlink_sb; | ||
1047 | int start = cb->args[0]; | ||
1048 | int idx = 0; | ||
1049 | int err; | ||
1050 | |||
1051 | mutex_lock(&devlink_mutex); | ||
1052 | mutex_lock(&devlink_port_mutex); | ||
1053 | list_for_each_entry(devlink, &devlink_list, list) { | ||
1054 | if (!net_eq(devlink_net(devlink), sock_net(msg->sk)) || | ||
1055 | !devlink->ops || !devlink->ops->sb_port_pool_get) | ||
1056 | continue; | ||
1057 | list_for_each_entry(devlink_sb, &devlink->sb_list, list) { | ||
1058 | err = __sb_port_pool_get_dumpit(msg, start, &idx, | ||
1059 | devlink, devlink_sb, | ||
1060 | NETLINK_CB(cb->skb).portid, | ||
1061 | cb->nlh->nlmsg_seq); | ||
1062 | if (err && err != -EOPNOTSUPP) | ||
1063 | goto out; | ||
1064 | } | ||
1065 | } | ||
1066 | out: | ||
1067 | mutex_unlock(&devlink_port_mutex); | ||
1068 | mutex_unlock(&devlink_mutex); | ||
1069 | |||
1070 | cb->args[0] = idx; | ||
1071 | return msg->len; | ||
1072 | } | ||
1073 | |||
1074 | static int devlink_sb_port_pool_set(struct devlink_port *devlink_port, | ||
1075 | unsigned int sb_index, u16 pool_index, | ||
1076 | u32 threshold) | ||
1077 | |||
1078 | { | ||
1079 | const struct devlink_ops *ops = devlink_port->devlink->ops; | ||
1080 | |||
1081 | if (ops && ops->sb_port_pool_set) | ||
1082 | return ops->sb_port_pool_set(devlink_port, sb_index, | ||
1083 | pool_index, threshold); | ||
1084 | return -EOPNOTSUPP; | ||
1085 | } | ||
1086 | |||
1087 | static int devlink_nl_cmd_sb_port_pool_set_doit(struct sk_buff *skb, | ||
1088 | struct genl_info *info) | ||
1089 | { | ||
1090 | struct devlink_port *devlink_port = info->user_ptr[0]; | ||
1091 | struct devlink_sb *devlink_sb = info->user_ptr[1]; | ||
1092 | u16 pool_index; | ||
1093 | u32 threshold; | ||
1094 | int err; | ||
1095 | |||
1096 | err = devlink_sb_pool_index_get_from_info(devlink_sb, info, | ||
1097 | &pool_index); | ||
1098 | if (err) | ||
1099 | return err; | ||
1100 | |||
1101 | if (!info->attrs[DEVLINK_ATTR_SB_THRESHOLD]) | ||
1102 | return -EINVAL; | ||
1103 | |||
1104 | threshold = nla_get_u32(info->attrs[DEVLINK_ATTR_SB_THRESHOLD]); | ||
1105 | return devlink_sb_port_pool_set(devlink_port, devlink_sb->index, | ||
1106 | pool_index, threshold); | ||
1107 | } | ||
1108 | |||
1109 | static int | ||
1110 | devlink_nl_sb_tc_pool_bind_fill(struct sk_buff *msg, struct devlink *devlink, | ||
1111 | struct devlink_port *devlink_port, | ||
1112 | struct devlink_sb *devlink_sb, u16 tc_index, | ||
1113 | enum devlink_sb_pool_type pool_type, | ||
1114 | enum devlink_command cmd, | ||
1115 | u32 portid, u32 seq, int flags) | ||
1116 | { | ||
1117 | u16 pool_index; | ||
1118 | u32 threshold; | ||
1119 | void *hdr; | ||
1120 | int err; | ||
1121 | |||
1122 | err = devlink->ops->sb_tc_pool_bind_get(devlink_port, devlink_sb->index, | ||
1123 | tc_index, pool_type, | ||
1124 | &pool_index, &threshold); | ||
1125 | if (err) | ||
1126 | return err; | ||
1127 | |||
1128 | hdr = genlmsg_put(msg, portid, seq, &devlink_nl_family, flags, cmd); | ||
1129 | if (!hdr) | ||
1130 | return -EMSGSIZE; | ||
1131 | |||
1132 | if (devlink_nl_put_handle(msg, devlink)) | ||
1133 | goto nla_put_failure; | ||
1134 | if (nla_put_u32(msg, DEVLINK_ATTR_PORT_INDEX, devlink_port->index)) | ||
1135 | goto nla_put_failure; | ||
1136 | if (nla_put_u32(msg, DEVLINK_ATTR_SB_INDEX, devlink_sb->index)) | ||
1137 | goto nla_put_failure; | ||
1138 | if (nla_put_u16(msg, DEVLINK_ATTR_SB_TC_INDEX, tc_index)) | ||
1139 | goto nla_put_failure; | ||
1140 | if (nla_put_u8(msg, DEVLINK_ATTR_SB_POOL_TYPE, pool_type)) | ||
1141 | goto nla_put_failure; | ||
1142 | if (nla_put_u16(msg, DEVLINK_ATTR_SB_POOL_INDEX, pool_index)) | ||
1143 | goto nla_put_failure; | ||
1144 | if (nla_put_u32(msg, DEVLINK_ATTR_SB_THRESHOLD, threshold)) | ||
1145 | goto nla_put_failure; | ||
1146 | |||
1147 | genlmsg_end(msg, hdr); | ||
1148 | return 0; | ||
1149 | |||
1150 | nla_put_failure: | ||
1151 | genlmsg_cancel(msg, hdr); | ||
1152 | return -EMSGSIZE; | ||
1153 | } | ||
1154 | |||
1155 | static int devlink_nl_cmd_sb_tc_pool_bind_get_doit(struct sk_buff *skb, | ||
1156 | struct genl_info *info) | ||
1157 | { | ||
1158 | struct devlink_port *devlink_port = info->user_ptr[0]; | ||
1159 | struct devlink *devlink = devlink_port->devlink; | ||
1160 | struct devlink_sb *devlink_sb = info->user_ptr[1]; | ||
1161 | struct sk_buff *msg; | ||
1162 | enum devlink_sb_pool_type pool_type; | ||
1163 | u16 tc_index; | ||
1164 | int err; | ||
1165 | |||
1166 | err = devlink_sb_pool_type_get_from_info(info, &pool_type); | ||
1167 | if (err) | ||
1168 | return err; | ||
1169 | |||
1170 | err = devlink_sb_tc_index_get_from_info(devlink_sb, info, | ||
1171 | pool_type, &tc_index); | ||
1172 | if (err) | ||
1173 | return err; | ||
1174 | |||
1175 | if (!devlink->ops || !devlink->ops->sb_tc_pool_bind_get) | ||
1176 | return -EOPNOTSUPP; | ||
1177 | |||
1178 | msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); | ||
1179 | if (!msg) | ||
1180 | return -ENOMEM; | ||
1181 | |||
1182 | err = devlink_nl_sb_tc_pool_bind_fill(msg, devlink, devlink_port, | ||
1183 | devlink_sb, tc_index, pool_type, | ||
1184 | DEVLINK_CMD_SB_TC_POOL_BIND_NEW, | ||
1185 | info->snd_portid, | ||
1186 | info->snd_seq, 0); | ||
1187 | if (err) { | ||
1188 | nlmsg_free(msg); | ||
1189 | return err; | ||
1190 | } | ||
1191 | |||
1192 | return genlmsg_reply(msg, info); | ||
1193 | } | ||
1194 | |||
1195 | static int __sb_tc_pool_bind_get_dumpit(struct sk_buff *msg, | ||
1196 | int start, int *p_idx, | ||
1197 | struct devlink *devlink, | ||
1198 | struct devlink_sb *devlink_sb, | ||
1199 | u32 portid, u32 seq) | ||
1200 | { | ||
1201 | struct devlink_port *devlink_port; | ||
1202 | u16 tc_index; | ||
1203 | int err; | ||
1204 | |||
1205 | list_for_each_entry(devlink_port, &devlink->port_list, list) { | ||
1206 | for (tc_index = 0; | ||
1207 | tc_index < devlink_sb->ingress_tc_count; tc_index++) { | ||
1208 | if (*p_idx < start) { | ||
1209 | (*p_idx)++; | ||
1210 | continue; | ||
1211 | } | ||
1212 | err = devlink_nl_sb_tc_pool_bind_fill(msg, devlink, | ||
1213 | devlink_port, | ||
1214 | devlink_sb, | ||
1215 | tc_index, | ||
1216 | DEVLINK_SB_POOL_TYPE_INGRESS, | ||
1217 | DEVLINK_CMD_SB_TC_POOL_BIND_NEW, | ||
1218 | portid, seq, | ||
1219 | NLM_F_MULTI); | ||
1220 | if (err) | ||
1221 | return err; | ||
1222 | (*p_idx)++; | ||
1223 | } | ||
1224 | for (tc_index = 0; | ||
1225 | tc_index < devlink_sb->egress_tc_count; tc_index++) { | ||
1226 | if (*p_idx < start) { | ||
1227 | (*p_idx)++; | ||
1228 | continue; | ||
1229 | } | ||
1230 | err = devlink_nl_sb_tc_pool_bind_fill(msg, devlink, | ||
1231 | devlink_port, | ||
1232 | devlink_sb, | ||
1233 | tc_index, | ||
1234 | DEVLINK_SB_POOL_TYPE_EGRESS, | ||
1235 | DEVLINK_CMD_SB_TC_POOL_BIND_NEW, | ||
1236 | portid, seq, | ||
1237 | NLM_F_MULTI); | ||
1238 | if (err) | ||
1239 | return err; | ||
1240 | (*p_idx)++; | ||
1241 | } | ||
1242 | } | ||
1243 | return 0; | ||
1244 | } | ||
1245 | |||
1246 | static int | ||
1247 | devlink_nl_cmd_sb_tc_pool_bind_get_dumpit(struct sk_buff *msg, | ||
1248 | struct netlink_callback *cb) | ||
1249 | { | ||
1250 | struct devlink *devlink; | ||
1251 | struct devlink_sb *devlink_sb; | ||
1252 | int start = cb->args[0]; | ||
1253 | int idx = 0; | ||
1254 | int err; | ||
1255 | |||
1256 | mutex_lock(&devlink_mutex); | ||
1257 | mutex_lock(&devlink_port_mutex); | ||
1258 | list_for_each_entry(devlink, &devlink_list, list) { | ||
1259 | if (!net_eq(devlink_net(devlink), sock_net(msg->sk)) || | ||
1260 | !devlink->ops || !devlink->ops->sb_tc_pool_bind_get) | ||
1261 | continue; | ||
1262 | list_for_each_entry(devlink_sb, &devlink->sb_list, list) { | ||
1263 | err = __sb_tc_pool_bind_get_dumpit(msg, start, &idx, | ||
1264 | devlink, | ||
1265 | devlink_sb, | ||
1266 | NETLINK_CB(cb->skb).portid, | ||
1267 | cb->nlh->nlmsg_seq); | ||
1268 | if (err && err != -EOPNOTSUPP) | ||
1269 | goto out; | ||
1270 | } | ||
1271 | } | ||
1272 | out: | ||
1273 | mutex_unlock(&devlink_port_mutex); | ||
1274 | mutex_unlock(&devlink_mutex); | ||
1275 | |||
1276 | cb->args[0] = idx; | ||
1277 | return msg->len; | ||
1278 | } | ||
1279 | |||
1280 | static int devlink_sb_tc_pool_bind_set(struct devlink_port *devlink_port, | ||
1281 | unsigned int sb_index, u16 tc_index, | ||
1282 | enum devlink_sb_pool_type pool_type, | ||
1283 | u16 pool_index, u32 threshold) | ||
1284 | |||
1285 | { | ||
1286 | const struct devlink_ops *ops = devlink_port->devlink->ops; | ||
1287 | |||
1288 | if (ops && ops->sb_tc_pool_bind_set) | ||
1289 | return ops->sb_tc_pool_bind_set(devlink_port, sb_index, | ||
1290 | tc_index, pool_type, | ||
1291 | pool_index, threshold); | ||
1292 | return -EOPNOTSUPP; | ||
1293 | } | ||
1294 | |||
1295 | static int devlink_nl_cmd_sb_tc_pool_bind_set_doit(struct sk_buff *skb, | ||
1296 | struct genl_info *info) | ||
1297 | { | ||
1298 | struct devlink_port *devlink_port = info->user_ptr[0]; | ||
1299 | struct devlink_sb *devlink_sb = info->user_ptr[1]; | ||
1300 | enum devlink_sb_pool_type pool_type; | ||
1301 | u16 tc_index; | ||
1302 | u16 pool_index; | ||
1303 | u32 threshold; | ||
1304 | int err; | ||
1305 | |||
1306 | err = devlink_sb_pool_type_get_from_info(info, &pool_type); | ||
1307 | if (err) | ||
1308 | return err; | ||
1309 | |||
1310 | err = devlink_sb_tc_index_get_from_info(devlink_sb, info, | ||
1311 | pool_type, &tc_index); | ||
1312 | if (err) | ||
1313 | return err; | ||
1314 | |||
1315 | err = devlink_sb_pool_index_get_from_info(devlink_sb, info, | ||
1316 | &pool_index); | ||
1317 | if (err) | ||
1318 | return err; | ||
1319 | |||
1320 | if (!info->attrs[DEVLINK_ATTR_SB_THRESHOLD]) | ||
1321 | return -EINVAL; | ||
1322 | |||
1323 | threshold = nla_get_u32(info->attrs[DEVLINK_ATTR_SB_THRESHOLD]); | ||
1324 | return devlink_sb_tc_pool_bind_set(devlink_port, devlink_sb->index, | ||
1325 | tc_index, pool_type, | ||
1326 | pool_index, threshold); | ||
1327 | } | ||
1328 | |||
502 | static const struct nla_policy devlink_nl_policy[DEVLINK_ATTR_MAX + 1] = { | 1329 | static const struct nla_policy devlink_nl_policy[DEVLINK_ATTR_MAX + 1] = { |
503 | [DEVLINK_ATTR_BUS_NAME] = { .type = NLA_NUL_STRING }, | 1330 | [DEVLINK_ATTR_BUS_NAME] = { .type = NLA_NUL_STRING }, |
504 | [DEVLINK_ATTR_DEV_NAME] = { .type = NLA_NUL_STRING }, | 1331 | [DEVLINK_ATTR_DEV_NAME] = { .type = NLA_NUL_STRING }, |
505 | [DEVLINK_ATTR_PORT_INDEX] = { .type = NLA_U32 }, | 1332 | [DEVLINK_ATTR_PORT_INDEX] = { .type = NLA_U32 }, |
506 | [DEVLINK_ATTR_PORT_TYPE] = { .type = NLA_U16 }, | 1333 | [DEVLINK_ATTR_PORT_TYPE] = { .type = NLA_U16 }, |
507 | [DEVLINK_ATTR_PORT_SPLIT_COUNT] = { .type = NLA_U32 }, | 1334 | [DEVLINK_ATTR_PORT_SPLIT_COUNT] = { .type = NLA_U32 }, |
1335 | [DEVLINK_ATTR_SB_INDEX] = { .type = NLA_U32 }, | ||
1336 | [DEVLINK_ATTR_SB_POOL_INDEX] = { .type = NLA_U16 }, | ||
1337 | [DEVLINK_ATTR_SB_POOL_TYPE] = { .type = NLA_U8 }, | ||
1338 | [DEVLINK_ATTR_SB_POOL_SIZE] = { .type = NLA_U32 }, | ||
1339 | [DEVLINK_ATTR_SB_POOL_THRESHOLD_TYPE] = { .type = NLA_U8 }, | ||
1340 | [DEVLINK_ATTR_SB_THRESHOLD] = { .type = NLA_U32 }, | ||
1341 | [DEVLINK_ATTR_SB_TC_INDEX] = { .type = NLA_U16 }, | ||
508 | }; | 1342 | }; |
509 | 1343 | ||
510 | static const struct genl_ops devlink_nl_ops[] = { | 1344 | static const struct genl_ops devlink_nl_ops[] = { |
@@ -545,6 +1379,66 @@ static const struct genl_ops devlink_nl_ops[] = { | |||
545 | .flags = GENL_ADMIN_PERM, | 1379 | .flags = GENL_ADMIN_PERM, |
546 | .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK, | 1380 | .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK, |
547 | }, | 1381 | }, |
1382 | { | ||
1383 | .cmd = DEVLINK_CMD_SB_GET, | ||
1384 | .doit = devlink_nl_cmd_sb_get_doit, | ||
1385 | .dumpit = devlink_nl_cmd_sb_get_dumpit, | ||
1386 | .policy = devlink_nl_policy, | ||
1387 | .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK | | ||
1388 | DEVLINK_NL_FLAG_NEED_SB, | ||
1389 | /* can be retrieved by unprivileged users */ | ||
1390 | }, | ||
1391 | { | ||
1392 | .cmd = DEVLINK_CMD_SB_POOL_GET, | ||
1393 | .doit = devlink_nl_cmd_sb_pool_get_doit, | ||
1394 | .dumpit = devlink_nl_cmd_sb_pool_get_dumpit, | ||
1395 | .policy = devlink_nl_policy, | ||
1396 | .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK | | ||
1397 | DEVLINK_NL_FLAG_NEED_SB, | ||
1398 | /* can be retrieved by unprivileged users */ | ||
1399 | }, | ||
1400 | { | ||
1401 | .cmd = DEVLINK_CMD_SB_POOL_SET, | ||
1402 | .doit = devlink_nl_cmd_sb_pool_set_doit, | ||
1403 | .policy = devlink_nl_policy, | ||
1404 | .flags = GENL_ADMIN_PERM, | ||
1405 | .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK | | ||
1406 | DEVLINK_NL_FLAG_NEED_SB, | ||
1407 | }, | ||
1408 | { | ||
1409 | .cmd = DEVLINK_CMD_SB_PORT_POOL_GET, | ||
1410 | .doit = devlink_nl_cmd_sb_port_pool_get_doit, | ||
1411 | .dumpit = devlink_nl_cmd_sb_port_pool_get_dumpit, | ||
1412 | .policy = devlink_nl_policy, | ||
1413 | .internal_flags = DEVLINK_NL_FLAG_NEED_PORT | | ||
1414 | DEVLINK_NL_FLAG_NEED_SB, | ||
1415 | /* can be retrieved by unprivileged users */ | ||
1416 | }, | ||
1417 | { | ||
1418 | .cmd = DEVLINK_CMD_SB_PORT_POOL_SET, | ||
1419 | .doit = devlink_nl_cmd_sb_port_pool_set_doit, | ||
1420 | .policy = devlink_nl_policy, | ||
1421 | .flags = GENL_ADMIN_PERM, | ||
1422 | .internal_flags = DEVLINK_NL_FLAG_NEED_PORT | | ||
1423 | DEVLINK_NL_FLAG_NEED_SB, | ||
1424 | }, | ||
1425 | { | ||
1426 | .cmd = DEVLINK_CMD_SB_TC_POOL_BIND_GET, | ||
1427 | .doit = devlink_nl_cmd_sb_tc_pool_bind_get_doit, | ||
1428 | .dumpit = devlink_nl_cmd_sb_tc_pool_bind_get_dumpit, | ||
1429 | .policy = devlink_nl_policy, | ||
1430 | .internal_flags = DEVLINK_NL_FLAG_NEED_PORT | | ||
1431 | DEVLINK_NL_FLAG_NEED_SB, | ||
1432 | /* can be retrieved by unprivileged users */ | ||
1433 | }, | ||
1434 | { | ||
1435 | .cmd = DEVLINK_CMD_SB_TC_POOL_BIND_SET, | ||
1436 | .doit = devlink_nl_cmd_sb_tc_pool_bind_set_doit, | ||
1437 | .policy = devlink_nl_policy, | ||
1438 | .flags = GENL_ADMIN_PERM, | ||
1439 | .internal_flags = DEVLINK_NL_FLAG_NEED_PORT | | ||
1440 | DEVLINK_NL_FLAG_NEED_SB, | ||
1441 | }, | ||
548 | }; | 1442 | }; |
549 | 1443 | ||
550 | /** | 1444 | /** |
@@ -566,6 +1460,7 @@ struct devlink *devlink_alloc(const struct devlink_ops *ops, size_t priv_size) | |||
566 | devlink->ops = ops; | 1460 | devlink->ops = ops; |
567 | devlink_net_set(devlink, &init_net); | 1461 | devlink_net_set(devlink, &init_net); |
568 | INIT_LIST_HEAD(&devlink->port_list); | 1462 | INIT_LIST_HEAD(&devlink->port_list); |
1463 | INIT_LIST_HEAD(&devlink->sb_list); | ||
569 | return devlink; | 1464 | return devlink; |
570 | } | 1465 | } |
571 | EXPORT_SYMBOL_GPL(devlink_alloc); | 1466 | EXPORT_SYMBOL_GPL(devlink_alloc); |
@@ -721,6 +1616,51 @@ void devlink_port_split_set(struct devlink_port *devlink_port, | |||
721 | } | 1616 | } |
722 | EXPORT_SYMBOL_GPL(devlink_port_split_set); | 1617 | EXPORT_SYMBOL_GPL(devlink_port_split_set); |
723 | 1618 | ||
1619 | int devlink_sb_register(struct devlink *devlink, unsigned int sb_index, | ||
1620 | u32 size, u16 ingress_pools_count, | ||
1621 | u16 egress_pools_count, u16 ingress_tc_count, | ||
1622 | u16 egress_tc_count) | ||
1623 | { | ||
1624 | struct devlink_sb *devlink_sb; | ||
1625 | int err = 0; | ||
1626 | |||
1627 | mutex_lock(&devlink_mutex); | ||
1628 | if (devlink_sb_index_exists(devlink, sb_index)) { | ||
1629 | err = -EEXIST; | ||
1630 | goto unlock; | ||
1631 | } | ||
1632 | |||
1633 | devlink_sb = kzalloc(sizeof(*devlink_sb), GFP_KERNEL); | ||
1634 | if (!devlink_sb) { | ||
1635 | err = -ENOMEM; | ||
1636 | goto unlock; | ||
1637 | } | ||
1638 | devlink_sb->index = sb_index; | ||
1639 | devlink_sb->size = size; | ||
1640 | devlink_sb->ingress_pools_count = ingress_pools_count; | ||
1641 | devlink_sb->egress_pools_count = egress_pools_count; | ||
1642 | devlink_sb->ingress_tc_count = ingress_tc_count; | ||
1643 | devlink_sb->egress_tc_count = egress_tc_count; | ||
1644 | list_add_tail(&devlink_sb->list, &devlink->sb_list); | ||
1645 | unlock: | ||
1646 | mutex_unlock(&devlink_mutex); | ||
1647 | return err; | ||
1648 | } | ||
1649 | EXPORT_SYMBOL_GPL(devlink_sb_register); | ||
1650 | |||
1651 | void devlink_sb_unregister(struct devlink *devlink, unsigned int sb_index) | ||
1652 | { | ||
1653 | struct devlink_sb *devlink_sb; | ||
1654 | |||
1655 | mutex_lock(&devlink_mutex); | ||
1656 | devlink_sb = devlink_sb_get_by_index(devlink, sb_index); | ||
1657 | WARN_ON(!devlink_sb); | ||
1658 | list_del(&devlink_sb->list); | ||
1659 | mutex_unlock(&devlink_mutex); | ||
1660 | kfree(devlink_sb); | ||
1661 | } | ||
1662 | EXPORT_SYMBOL_GPL(devlink_sb_unregister); | ||
1663 | |||
724 | static int __init devlink_module_init(void) | 1664 | static int __init devlink_module_init(void) |
725 | { | 1665 | { |
726 | return genl_register_family_with_ops_groups(&devlink_nl_family, | 1666 | return genl_register_family_with_ops_groups(&devlink_nl_family, |