libnl  3.7.0
prio.c
1 /* SPDX-License-Identifier: LGPL-2.1-only */
2 /*
3  * Copyright (c) 2003-2011 Thomas Graf <tgraf@suug.ch>
4  */
5 
6 /**
7  * @ingroup qdisc
8  * @defgroup qdisc_prio (Fast) Prio
9  * @brief
10  *
11  * @par 1) Typical PRIO configuration
12  * @code
13  * // Specify the maximal number of bands to be used for this PRIO qdisc.
14  * rtnl_qdisc_prio_set_bands(qdisc, QDISC_PRIO_DEFAULT_BANDS);
15  *
16  * // Provide a map assigning each priority to a band number.
17  * uint8_t map[] = QDISC_PRIO_DEFAULT_PRIOMAP;
18  * rtnl_qdisc_prio_set_priomap(qdisc, map, sizeof(map));
19  * @endcode
20  * @{
21  */
22 
23 #include <netlink-private/netlink.h>
24 #include <netlink-private/tc.h>
25 #include <netlink/netlink.h>
26 #include <netlink/utils.h>
27 #include <netlink-private/route/tc-api.h>
28 #include <netlink/route/qdisc.h>
29 #include <netlink/route/qdisc/prio.h>
30 
31 /** @cond SKIP */
32 #define SCH_PRIO_ATTR_BANDS 1
33 #define SCH_PRIO_ATTR_PRIOMAP 2
34 /** @endcond */
35 
36 static int prio_msg_parser(struct rtnl_tc *tc, void *data)
37 {
38  struct rtnl_prio *prio = data;
39  struct tc_prio_qopt *opt;
40 
41  if (tc->tc_opts->d_size < sizeof(*opt))
42  return -NLE_INVAL;
43 
44  opt = (struct tc_prio_qopt *) tc->tc_opts->d_data;
45  prio->qp_bands = opt->bands;
46  memcpy(prio->qp_priomap, opt->priomap, sizeof(prio->qp_priomap));
47  prio->qp_mask = (SCH_PRIO_ATTR_BANDS | SCH_PRIO_ATTR_PRIOMAP);
48 
49  return 0;
50 }
51 
52 static void prio_dump_line(struct rtnl_tc *tc, void *data,
53  struct nl_dump_params *p)
54 {
55  struct rtnl_prio *prio = data;
56 
57  if (prio)
58  nl_dump(p, " bands %u", prio->qp_bands);
59 }
60 
61 static void prio_dump_details(struct rtnl_tc *tc, void *data,
62  struct nl_dump_params *p)
63 {
64  struct rtnl_prio *prio = data;
65  int i, hp;
66 
67  if (!prio)
68  return;
69 
70  nl_dump(p, "priomap [");
71 
72  for (i = 0; i <= TC_PRIO_MAX; i++)
73  nl_dump(p, "%u%s", prio->qp_priomap[i],
74  i < TC_PRIO_MAX ? " " : "");
75 
76  nl_dump(p, "]\n");
77  nl_new_line(p);
78 
79  hp = (((TC_PRIO_MAX/2) + 1) & ~1);
80 
81  for (i = 0; i < hp; i++) {
82  char a[32];
83  nl_dump(p, " %18s => %u",
84  rtnl_prio2str(i, a, sizeof(a)),
85  prio->qp_priomap[i]);
86  if (hp+i <= TC_PRIO_MAX) {
87  nl_dump(p, " %18s => %u",
88  rtnl_prio2str(hp+i, a, sizeof(a)),
89  prio->qp_priomap[hp+i]);
90  if (i < (hp - 1)) {
91  nl_dump(p, "\n");
92  nl_new_line(p);
93  }
94  }
95  }
96 }
97 
98 static int prio_msg_fill(struct rtnl_tc *tc, void *data, struct nl_msg *msg)
99 {
100  struct rtnl_prio *prio = data;
101  struct tc_prio_qopt opts;
102 
103  if (!prio || !(prio->qp_mask & SCH_PRIO_ATTR_PRIOMAP))
104  BUG();
105 
106  opts.bands = prio->qp_bands;
107  memcpy(opts.priomap, prio->qp_priomap, sizeof(opts.priomap));
108 
109  return nlmsg_append(msg, &opts, sizeof(opts), NL_DONTPAD);
110 }
111 
112 /**
113  * @name Attribute Modification
114  * @{
115  */
116 
117 /**
118  * Set number of bands of PRIO qdisc.
119  * @arg qdisc PRIO qdisc to be modified.
120  * @arg bands New number of bands.
121  * @return 0 on success or a negative error code.
122  */
123 void rtnl_qdisc_prio_set_bands(struct rtnl_qdisc *qdisc, int bands)
124 {
125  struct rtnl_prio *prio;
126 
127  if (!(prio = rtnl_tc_data(TC_CAST(qdisc))))
128  BUG();
129 
130  prio->qp_bands = bands;
131  prio->qp_mask |= SCH_PRIO_ATTR_BANDS;
132 }
133 
134 /**
135  * Get number of bands of PRIO qdisc.
136  * @arg qdisc PRIO qdisc.
137  * @return Number of bands or a negative error code.
138  */
139 int rtnl_qdisc_prio_get_bands(struct rtnl_qdisc *qdisc)
140 {
141  struct rtnl_prio *prio;
142 
143  if (!(prio = rtnl_tc_data(TC_CAST(qdisc))))
144  BUG();
145 
146  if (prio->qp_mask & SCH_PRIO_ATTR_BANDS)
147  return prio->qp_bands;
148  else
149  return -NLE_NOMEM;
150 }
151 
152 /**
153  * Set priomap of the PRIO qdisc.
154  * @arg qdisc PRIO qdisc to be modified.
155  * @arg priomap New priority mapping.
156  * @arg len Length of priomap (# of elements).
157  * @return 0 on success or a negative error code.
158  */
159 int rtnl_qdisc_prio_set_priomap(struct rtnl_qdisc *qdisc, uint8_t priomap[],
160  int len)
161 {
162  struct rtnl_prio *prio;
163  int i;
164 
165  if (!(prio = rtnl_tc_data(TC_CAST(qdisc))))
166  BUG();
167 
168  if (!(prio->qp_mask & SCH_PRIO_ATTR_BANDS))
169  return -NLE_MISSING_ATTR;
170 
171  if ((len / sizeof(uint8_t)) > (TC_PRIO_MAX+1))
172  return -NLE_RANGE;
173 
174  for (i = 0; i <= TC_PRIO_MAX; i++) {
175  if (priomap[i] > prio->qp_bands)
176  return -NLE_RANGE;
177  }
178 
179  memcpy(prio->qp_priomap, priomap, len);
180  prio->qp_mask |= SCH_PRIO_ATTR_PRIOMAP;
181 
182  return 0;
183 }
184 
185 /**
186  * Get priomap of a PRIO qdisc.
187  * @arg qdisc PRIO qdisc.
188  * @return Priority mapping as array of size TC_PRIO_MAX+1
189  * or NULL if an error occured.
190  */
191 uint8_t *rtnl_qdisc_prio_get_priomap(struct rtnl_qdisc *qdisc)
192 {
193  struct rtnl_prio *prio;
194 
195  if (!(prio = rtnl_tc_data(TC_CAST(qdisc))))
196  BUG();
197 
198  if (prio->qp_mask & SCH_PRIO_ATTR_PRIOMAP)
199  return prio->qp_priomap;
200  else
201  return NULL;
202 }
203 
204 /** @} */
205 
206 /**
207  * @name Priority Band Translations
208  * @{
209  */
210 
211 static const struct trans_tbl prios[] = {
212  __ADD(TC_PRIO_BESTEFFORT,besteffort),
213  __ADD(TC_PRIO_FILLER,filler),
214  __ADD(TC_PRIO_BULK,bulk),
215  __ADD(TC_PRIO_INTERACTIVE_BULK,interactive_bulk),
216  __ADD(TC_PRIO_INTERACTIVE,interactive),
217  __ADD(TC_PRIO_CONTROL,control),
218 };
219 
220 /**
221  * Convert priority to character string.
222  * @arg prio Priority.
223  * @arg buf Destination buffer
224  * @arg size Size of destination buffer.
225  *
226  * Converts a priority to a character string and stores the result in
227  * the specified destination buffer.
228  *
229  * @return Name of priority as character string.
230  */
231 char * rtnl_prio2str(int prio, char *buf, size_t size)
232 {
233  return __type2str(prio, buf, size, prios, ARRAY_SIZE(prios));
234 }
235 
236 /**
237  * Convert character string to priority.
238  * @arg name Name of priority.
239  *
240  * Converts the provided character string specifying a priority
241  * to the corresponding numeric value.
242  *
243  * @return Numeric priority or a negative value if no match was found.
244  */
245 int rtnl_str2prio(const char *name)
246 {
247  return __str2type(name, prios, ARRAY_SIZE(prios));
248 }
249 
250 /** @} */
251 
252 static struct rtnl_tc_ops prio_ops = {
253  .to_kind = "prio",
254  .to_type = RTNL_TC_TYPE_QDISC,
255  .to_size = sizeof(struct rtnl_prio),
256  .to_msg_parser = prio_msg_parser,
257  .to_dump = {
258  [NL_DUMP_LINE] = prio_dump_line,
259  [NL_DUMP_DETAILS] = prio_dump_details,
260  },
261  .to_msg_fill = prio_msg_fill,
262 };
263 
264 static struct rtnl_tc_ops pfifo_fast_ops = {
265  .to_kind = "pfifo_fast",
266  .to_type = RTNL_TC_TYPE_QDISC,
267  .to_size = sizeof(struct rtnl_prio),
268  .to_msg_parser = prio_msg_parser,
269  .to_dump = {
270  [NL_DUMP_LINE] = prio_dump_line,
271  [NL_DUMP_DETAILS] = prio_dump_details,
272  },
273  .to_msg_fill = prio_msg_fill,
274 };
275 
276 static void __init prio_init(void)
277 {
278  rtnl_tc_register(&prio_ops);
279  rtnl_tc_register(&pfifo_fast_ops);
280 }
281 
282 static void __exit prio_exit(void)
283 {
284  rtnl_tc_unregister(&prio_ops);
285  rtnl_tc_unregister(&pfifo_fast_ops);
286 }
287 
288 /** @} */
int nlmsg_append(struct nl_msg *n, void *data, size_t len, int pad)
Append data to tail of a netlink message.
Definition: msg.c:442
char * rtnl_prio2str(int prio, char *buf, size_t size)
Convert priority to character string.
Definition: prio.c:231
int rtnl_qdisc_prio_get_bands(struct rtnl_qdisc *qdisc)
Get number of bands of PRIO qdisc.
Definition: prio.c:139
int rtnl_str2prio(const char *name)
Convert character string to priority.
Definition: prio.c:245
int rtnl_qdisc_prio_set_priomap(struct rtnl_qdisc *qdisc, uint8_t priomap[], int len)
Set priomap of the PRIO qdisc.
Definition: prio.c:159
void rtnl_qdisc_prio_set_bands(struct rtnl_qdisc *qdisc, int bands)
Set number of bands of PRIO qdisc.
Definition: prio.c:123
uint8_t * rtnl_qdisc_prio_get_priomap(struct rtnl_qdisc *qdisc)
Get priomap of a PRIO qdisc.
Definition: prio.c:191
void * rtnl_tc_data(struct rtnl_tc *tc)
Return pointer to private data of traffic control object.
Definition: tc.c:1076
#define TC_CAST(ptr)
Macro to cast qdisc/class/classifier to tc object.
Definition: tc.h:50
int rtnl_tc_register(struct rtnl_tc_ops *ops)
Register a traffic control module.
Definition: tc.c:1015
void rtnl_tc_unregister(struct rtnl_tc_ops *ops)
Unregister a traffic control module.
Definition: tc.c:1049
void nl_dump(struct nl_dump_params *params, const char *fmt,...)
Dump a formatted character string.
Definition: utils.c:955
void nl_new_line(struct nl_dump_params *params)
Handle a new line while dumping.
Definition: utils.c:906
@ NL_DUMP_LINE
Dump object briefly on one line.
Definition: types.h:16
@ NL_DUMP_DETAILS
Dump all attributes but no statistics.
Definition: types.h:17
Dumping parameters.
Definition: types.h:28