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