History

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.

Jiri Pirko committed 10 years ago

Commit bf797471 parent f38ba953 files · +1044 −0Browse files

Unified · Split

3 files
  1. include/net/devlink.h +47 −0
  2. include/uapi/linux/devlink.h +57 −0
  3. net/core/devlink.c +940 −0
include/net/devlink.h+47−0
@@ -24,6 +24,7 @@ struct devlink_ops; · 23 unmodified lines
2424 struct devlink {
2525 struct list_head list;
2626 struct list_head port_list;
27+ struct list_head sb_list;
2728 const struct devlink_ops *ops;
2829 struct device *dev;
2930 possible_net_t _net;
@@ -42,6 +43,12 @@ struct devlink_port { · 12 unmodified lines
4243 u32 split_group;
4344 };
4445
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+
4552 struct devlink_ops {
4653 size_t priv_size;
4754 int (*port_type_set)(struct devlink_port *devlink_port,
@@ -49,6 +56,28 @@ struct devlink_ops { · 1 unmodified line
4956 int (*port_split)(struct devlink *devlink, unsigned int port_index,
5057 unsigned int count);
5158 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);
5281 };
5382
5483 static inline void *devlink_priv(struct devlink *devlink)
@@ -82,6 +111,11 @@ void devlink_port_type_ib_set(struct devlink_port *devlink_port, · 27 unmodified lines
82111 void devlink_port_type_clear(struct devlink_port *devlink_port);
83112 void devlink_port_split_set(struct devlink_port *devlink_port,
84113 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);
85119
86120 #else
87121
@@ -135,6 +169,19 @@ static inline void devlink_port_split_set(struct devlink_port *devlink_port, · 47 unmodified lines
135169 {
136170 }
137171
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+
138185 #endif
139186
140187 #endif /* _NET_DEVLINK_H_ */
include/uapi/linux/devlink.h+57−0
@@ -33,6 +33,26 @@ enum devlink_command { · 32 unmodified lines
3333 DEVLINK_CMD_PORT_SPLIT,
3434 DEVLINK_CMD_PORT_UNSPLIT,
3535
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+
3656 /* add new commands above here */
3757
3858 __DEVLINK_CMD_MAX,
@@ -46,6 +66,31 @@ enum devlink_port_type { · 7 unmodified lines
4666 DEVLINK_PORT_TYPE_IB,
4767 };
4868
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+
4994 enum devlink_attr {
5095 /* don't change the order or add anything between, this is ABI! */
5196 DEVLINK_ATTR_UNSPEC,
@@ -62,6 +107,18 @@ enum devlink_attr { · 10 unmodified lines
62107 DEVLINK_ATTR_PORT_IBDEV_NAME, /* string */
63108 DEVLINK_ATTR_PORT_SPLIT_COUNT, /* u32 */
64109 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 */
65122
66123 /* add new attributes above here, update the policy in devlink.c */
67124
net/core/devlink.c+940−0
@@ -119,8 +119,167 @@ static struct devlink_port *devlink_port_get_from_info(struct devlink *devlink, · 118 unmodified lines
119119 return devlink_port_get_from_attrs(devlink, info->attrs);
120120 }
121121
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+
122280 #define DEVLINK_NL_FLAG_NEED_DEVLINK BIT(0)
123281 #define DEVLINK_NL_FLAG_NEED_PORT BIT(1)
282+#define DEVLINK_NL_FLAG_NEED_SB BIT(2)
124283
125284 static int devlink_nl_pre_doit(const struct genl_ops *ops,
126285 struct sk_buff *skb, struct genl_info *info)
@@ -147,6 +306,18 @@ static int devlink_nl_pre_doit(const struct genl_ops *ops, · 20 unmodified lines
147306 }
148307 info->user_ptr[0] = devlink_port;
149308 }
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+ }
150321 return 0;
151322 }
152323
@@ -499,12 +670,675 @@ static int devlink_nl_cmd_port_unsplit_doit(struct sk_buff *skb, · 346 unmodified lines
499670 return devlink_port_unsplit(devlink, port_index);
500671 }
501672
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+
5021329 static const struct nla_policy devlink_nl_policy[DEVLINK_ATTR_MAX + 1] = {
5031330 [DEVLINK_ATTR_BUS_NAME] = { .type = NLA_NUL_STRING },
5041331 [DEVLINK_ATTR_DEV_NAME] = { .type = NLA_NUL_STRING },
5051332 [DEVLINK_ATTR_PORT_INDEX] = { .type = NLA_U32 },
5061333 [DEVLINK_ATTR_PORT_TYPE] = { .type = NLA_U16 },
5071334 [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 },
5081342 };
5091343
5101344 static const struct genl_ops devlink_nl_ops[] = {
@@ -545,6 +1379,66 @@ static const struct genl_ops devlink_nl_ops[] = { · 34 unmodified lines
5451379 .flags = GENL_ADMIN_PERM,
5461380 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK,
5471381 },
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+ },
5481442 };
5491443
5501444 /**
@@ -566,6 +1460,7 @@ struct devlink *devlink_alloc(const struct devlink_ops *ops, size_t priv_size) · 15 unmodified lines
5661460 devlink->ops = ops;
5671461 devlink_net_set(devlink, &init_net);
5681462 INIT_LIST_HEAD(&devlink->port_list);
1463+ INIT_LIST_HEAD(&devlink->sb_list);
5691464 return devlink;
5701465 }
5711466 EXPORT_SYMBOL_GPL(devlink_alloc);
@@ -721,6 +1616,51 @@ void devlink_port_split_set(struct devlink_port *devlink_port, · 149 unmodified lines
7211616 }
7221617 EXPORT_SYMBOL_GPL(devlink_port_split_set);
7231618
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+
7241664 static int __init devlink_module_init(void)
7251665 {
7261666 return genl_register_family_with_ops_groups(&devlink_nl_family,