aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJiri Pirko <jiri@mellanox.com>2016-04-14 12:19:13 -0400
committerDavid S. Miller <davem@davemloft.net>2016-04-14 16:22:03 -0400
commitbf7974710a40aaeb69dee7f62d91048bdaf79c76 (patch)
treeadff44085782f226cbb473dae79bd04024b507b7
parentf38ba953bee01887d520f7abba536721a1d16477 (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.h47
-rw-r--r--include/uapi/linux/devlink.h57
-rw-r--r--net/core/devlink.c940
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;
24struct devlink { 24struct 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
46struct 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
45struct devlink_ops { 52struct 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
54static inline void *devlink_priv(struct devlink *devlink) 83static inline void *devlink_priv(struct devlink *devlink)
@@ -82,6 +111,11 @@ void devlink_port_type_ib_set(struct devlink_port *devlink_port,
82void devlink_port_type_clear(struct devlink_port *devlink_port); 111void devlink_port_type_clear(struct devlink_port *devlink_port);
83void devlink_port_split_set(struct devlink_port *devlink_port, 112void devlink_port_split_set(struct devlink_port *devlink_port,
84 u32 split_group); 113 u32 split_group);
114int 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);
118void 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
172static 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
180static 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
69enum 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
87enum 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
49enum devlink_attr { 94enum 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
122struct 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
132static 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
137static 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
149static 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
155static 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
170static 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
176static 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
192static 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
200static int
201devlink_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
217static int
218devlink_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
224static int
225devlink_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
241static int
242devlink_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
248static int
249devlink_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
270static int
271devlink_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
125static int devlink_nl_pre_doit(const struct genl_ops *ops, 284static 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
673static 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
706nla_put_failure:
707 genlmsg_cancel(msg, hdr);
708 return -EMSGSIZE;
709}
710
711static 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
734static 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 }
762out:
763 mutex_unlock(&devlink_mutex);
764
765 cb->args[0] = idx;
766 return msg->len;
767}
768
769static 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
804nla_put_failure:
805 genlmsg_cancel(msg, hdr);
806 return -EMSGSIZE;
807}
808
809static 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
841static 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
867static 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 }
890out:
891 mutex_unlock(&devlink_mutex);
892
893 cb->args[0] = idx;
894 return msg->len;
895}
896
897static 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
910static 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
937static 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
972nla_put_failure:
973 genlmsg_cancel(msg, hdr);
974 return -EMSGSIZE;
975}
976
977static 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
1011static 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
1042static 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 }
1066out:
1067 mutex_unlock(&devlink_port_mutex);
1068 mutex_unlock(&devlink_mutex);
1069
1070 cb->args[0] = idx;
1071 return msg->len;
1072}
1073
1074static 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
1087static 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
1109static int
1110devlink_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
1150nla_put_failure:
1151 genlmsg_cancel(msg, hdr);
1152 return -EMSGSIZE;
1153}
1154
1155static 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
1195static 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
1246static int
1247devlink_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 }
1272out:
1273 mutex_unlock(&devlink_port_mutex);
1274 mutex_unlock(&devlink_mutex);
1275
1276 cb->args[0] = idx;
1277 return msg->len;
1278}
1279
1280static 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
1295static 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
502static const struct nla_policy devlink_nl_policy[DEVLINK_ATTR_MAX + 1] = { 1329static 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
510static const struct genl_ops devlink_nl_ops[] = { 1344static 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}
571EXPORT_SYMBOL_GPL(devlink_alloc); 1466EXPORT_SYMBOL_GPL(devlink_alloc);
@@ -721,6 +1616,51 @@ void devlink_port_split_set(struct devlink_port *devlink_port,
721} 1616}
722EXPORT_SYMBOL_GPL(devlink_port_split_set); 1617EXPORT_SYMBOL_GPL(devlink_port_split_set);
723 1618
1619int 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);
1645unlock:
1646 mutex_unlock(&devlink_mutex);
1647 return err;
1648}
1649EXPORT_SYMBOL_GPL(devlink_sb_register);
1650
1651void 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}
1662EXPORT_SYMBOL_GPL(devlink_sb_unregister);
1663
724static int __init devlink_module_init(void) 1664static 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,