1 /* SPDX-License-Identifier: LGPL-2.1-or-later
2 * Copyright © 2020 VMware, Inc. */
3
4 #include <linux/pkt_sched.h>
5
6 #include "parse-util.h"
7 #include "qdisc.h"
8 #include "qfq.h"
9 #include "string-util.h"
10
11 #define QFQ_MAX_WEIGHT (1 << 10)
12 #define QFQ_MIN_MAX_PACKET 512
13 #define QFQ_MAX_MAX_PACKET (1 << 16)
14
15 const QDiscVTable qfq_vtable = {
16 .object_size = sizeof(QuickFairQueueing),
17 .tca_kind = "qfq",
18 };
19
quick_fair_queueing_class_fill_message(Link * link,TClass * tclass,sd_netlink_message * req)20 static int quick_fair_queueing_class_fill_message(Link *link, TClass *tclass, sd_netlink_message *req) {
21 QuickFairQueueingClass *qfq;
22 int r;
23
24 assert(link);
25 assert(tclass);
26 assert(req);
27
28 assert_se(qfq = TCLASS_TO_QFQ(tclass));
29
30 r = sd_netlink_message_open_container_union(req, TCA_OPTIONS, "qfq");
31 if (r < 0)
32 return r;
33
34 if (qfq->weight > 0) {
35 r = sd_netlink_message_append_u32(req, TCA_QFQ_WEIGHT, qfq->weight);
36 if (r < 0)
37 return r;
38 }
39
40 if (qfq->max_packet > 0) {
41 r = sd_netlink_message_append_u32(req, TCA_QFQ_LMAX, qfq->max_packet);
42 if (r < 0)
43 return r;
44 }
45
46 r = sd_netlink_message_close_container(req);
47 if (r < 0)
48 return r;
49
50 return 0;
51 }
52
config_parse_quick_fair_queueing_weight(const char * unit,const char * filename,unsigned line,const char * section,unsigned section_line,const char * lvalue,int ltype,const char * rvalue,void * data,void * userdata)53 int config_parse_quick_fair_queueing_weight(
54 const char *unit,
55 const char *filename,
56 unsigned line,
57 const char *section,
58 unsigned section_line,
59 const char *lvalue,
60 int ltype,
61 const char *rvalue,
62 void *data,
63 void *userdata) {
64
65 _cleanup_(tclass_free_or_set_invalidp) TClass *tclass = NULL;
66 QuickFairQueueingClass *qfq;
67 Network *network = data;
68 uint32_t v;
69 int r;
70
71 assert(filename);
72 assert(lvalue);
73 assert(rvalue);
74 assert(data);
75
76 r = tclass_new_static(TCLASS_KIND_QFQ, network, filename, section_line, &tclass);
77 if (r == -ENOMEM)
78 return log_oom();
79 if (r < 0) {
80 log_syntax(unit, LOG_WARNING, filename, line, r,
81 "Failed to create traffic control class, ignoring assignment: %m");
82 return 0;
83 }
84
85 qfq = TCLASS_TO_QFQ(tclass);
86
87 if (isempty(rvalue)) {
88 qfq->weight = 0;
89 TAKE_PTR(tclass);
90 return 0;
91 }
92
93 r = safe_atou32(rvalue, &v);
94 if (r < 0) {
95 log_syntax(unit, LOG_WARNING, filename, line, r,
96 "Failed to parse '%s=', ignoring assignment: %s",
97 lvalue, rvalue);
98 return 0;
99 }
100
101 if (v == 0 || v > QFQ_MAX_WEIGHT) {
102 log_syntax(unit, LOG_WARNING, filename, line, 0,
103 "Invalid '%s=', ignoring assignment: %s",
104 lvalue, rvalue);
105 return 0;
106 }
107
108 qfq->weight = v;
109 TAKE_PTR(tclass);
110
111 return 0;
112 }
113
config_parse_quick_fair_queueing_max_packet(const char * unit,const char * filename,unsigned line,const char * section,unsigned section_line,const char * lvalue,int ltype,const char * rvalue,void * data,void * userdata)114 int config_parse_quick_fair_queueing_max_packet(
115 const char *unit,
116 const char *filename,
117 unsigned line,
118 const char *section,
119 unsigned section_line,
120 const char *lvalue,
121 int ltype,
122 const char *rvalue,
123 void *data,
124 void *userdata) {
125
126 _cleanup_(tclass_free_or_set_invalidp) TClass *tclass = NULL;
127 QuickFairQueueingClass *qfq;
128 Network *network = data;
129 uint64_t v;
130 int r;
131
132 assert(filename);
133 assert(lvalue);
134 assert(rvalue);
135 assert(data);
136
137 r = tclass_new_static(TCLASS_KIND_QFQ, network, filename, section_line, &tclass);
138 if (r == -ENOMEM)
139 return log_oom();
140 if (r < 0) {
141 log_syntax(unit, LOG_WARNING, filename, line, r,
142 "Failed to create traffic control class, ignoring assignment: %m");
143 return 0;
144 }
145
146 qfq = TCLASS_TO_QFQ(tclass);
147
148 if (isempty(rvalue)) {
149 qfq->max_packet = 0;
150 TAKE_PTR(tclass);
151 return 0;
152 }
153
154 r = parse_size(rvalue, 1024, &v);
155 if (r < 0) {
156 log_syntax(unit, LOG_WARNING, filename, line, r,
157 "Failed to parse '%s=', ignoring assignment: %s",
158 lvalue, rvalue);
159 return 0;
160 }
161
162 if (v < QFQ_MIN_MAX_PACKET || v > QFQ_MAX_MAX_PACKET) {
163 log_syntax(unit, LOG_WARNING, filename, line, 0,
164 "Invalid '%s=', ignoring assignment: %s",
165 lvalue, rvalue);
166 return 0;
167 }
168
169 qfq->max_packet = (uint32_t) v;
170 TAKE_PTR(tclass);
171
172 return 0;
173 }
174
175 const TClassVTable qfq_tclass_vtable = {
176 .object_size = sizeof(QuickFairQueueingClass),
177 .tca_kind = "qfq",
178 .fill_message = quick_fair_queueing_class_fill_message,
179 };
180