1 // SPDX-License-Identifier: GPL-2.0+
3 * Copyright (C) 2021 Felix Fietkau <nbd@nbd.name>
9 static struct blob_buf b
;
12 qosify_ubus_add_array(struct blob_attr
*attr
, uint8_t val
, enum qosify_map_id id
)
14 struct blob_attr
*cur
;
17 if (blobmsg_check_array(attr
, BLOBMSG_TYPE_STRING
) < 0)
18 return UBUS_STATUS_INVALID_ARGUMENT
;
20 blobmsg_for_each_attr(cur
, attr
, rem
)
21 qosify_map_set_entry(id
, false, blobmsg_get_string(cur
), val
);
27 qosify_ubus_set_files(struct blob_attr
*attr
)
29 struct blob_attr
*cur
;
32 if (blobmsg_check_array(attr
, BLOBMSG_TYPE_STRING
) < 0)
33 return UBUS_STATUS_INVALID_ARGUMENT
;
35 qosify_map_clear_files();
37 blobmsg_for_each_attr(cur
, attr
, rem
)
38 qosify_map_load_file(blobmsg_get_string(cur
));
57 static const struct blobmsg_policy qosify_add_policy
[__CL_ADD_MAX
] = {
58 [CL_ADD_DSCP
] = { "dscp", BLOBMSG_TYPE_STRING
},
59 [CL_ADD_TIMEOUT
] = { "timeout", BLOBMSG_TYPE_INT32
},
60 [CL_ADD_IPV4
] = { "ipv4", BLOBMSG_TYPE_ARRAY
},
61 [CL_ADD_IPV6
] = { "ipv6", BLOBMSG_TYPE_ARRAY
},
62 [CL_ADD_TCP_PORT
] = { "tcp_port", BLOBMSG_TYPE_ARRAY
},
63 [CL_ADD_UDP_PORT
] = { "udp_port", BLOBMSG_TYPE_ARRAY
},
64 [CL_ADD_DNS
] = { "dns", BLOBMSG_TYPE_ARRAY
},
69 qosify_ubus_reload(struct ubus_context
*ctx
, struct ubus_object
*obj
,
70 struct ubus_request_data
*req
, const char *method
,
71 struct blob_attr
*msg
)
79 qosify_ubus_add(struct ubus_context
*ctx
, struct ubus_object
*obj
,
80 struct ubus_request_data
*req
, const char *method
,
81 struct blob_attr
*msg
)
83 int prev_timemout
= qosify_map_timeout
;
84 struct blob_attr
*tb
[__CL_ADD_MAX
];
85 struct blob_attr
*cur
;
89 blobmsg_parse(qosify_add_policy
, __CL_ADD_MAX
, tb
,
90 blobmsg_data(msg
), blobmsg_len(msg
));
92 if (!strcmp(method
, "add")) {
93 if ((cur
= tb
[CL_ADD_DSCP
]) != NULL
)
94 dscp
= qosify_map_dscp_value(blobmsg_get_string(cur
));
96 return UBUS_STATUS_INVALID_ARGUMENT
;
98 return UBUS_STATUS_INVALID_ARGUMENT
;
100 if ((cur
= tb
[CL_ADD_TIMEOUT
]) != NULL
)
101 qosify_map_timeout
= blobmsg_get_u32(cur
);
106 if ((cur
= tb
[CL_ADD_IPV4
]) != NULL
&&
107 (ret
= qosify_ubus_add_array(cur
, dscp
, CL_MAP_IPV4_ADDR
) != 0))
110 if ((cur
= tb
[CL_ADD_IPV6
]) != NULL
&&
111 (ret
= qosify_ubus_add_array(cur
, dscp
, CL_MAP_IPV6_ADDR
) != 0))
114 if ((cur
= tb
[CL_ADD_TCP_PORT
]) != NULL
&&
115 (ret
= qosify_ubus_add_array(cur
, dscp
, CL_MAP_TCP_PORTS
) != 0))
118 if ((cur
= tb
[CL_ADD_UDP_PORT
]) != NULL
&&
119 (ret
= qosify_ubus_add_array(cur
, dscp
, CL_MAP_UDP_PORTS
) != 0))
122 if ((cur
= tb
[CL_ADD_DNS
]) != NULL
&&
123 (ret
= qosify_ubus_add_array(cur
, dscp
, CL_MAP_DNS
) != 0))
126 qosify_map_timeout
= prev_timemout
;
140 CL_CONFIG_BULK_TIMEOUT
,
142 CL_CONFIG_PRIO_PKT_LEN
,
143 CL_CONFIG_INTERFACES
,
148 static const struct blobmsg_policy qosify_config_policy
[__CL_CONFIG_MAX
] = {
149 [CL_CONFIG_RESET
] = { "reset", BLOBMSG_TYPE_BOOL
},
150 [CL_CONFIG_FILES
] = { "files", BLOBMSG_TYPE_ARRAY
},
151 [CL_CONFIG_TIMEOUT
] = { "timeout", BLOBMSG_TYPE_INT32
},
152 [CL_CONFIG_DSCP_UDP
] = { "dscp_default_udp", BLOBMSG_TYPE_STRING
},
153 [CL_CONFIG_DSCP_TCP
] = { "dscp_default_tcp", BLOBMSG_TYPE_STRING
},
154 [CL_CONFIG_DSCP_PRIO
] = { "dscp_prio", BLOBMSG_TYPE_STRING
},
155 [CL_CONFIG_DSCP_BULK
] = { "dscp_bulk", BLOBMSG_TYPE_STRING
},
156 [CL_CONFIG_DSCP_ICMP
] = { "dscp_icmp", BLOBMSG_TYPE_STRING
},
157 [CL_CONFIG_BULK_TIMEOUT
] = { "bulk_trigger_timeout", BLOBMSG_TYPE_INT32
},
158 [CL_CONFIG_BULK_PPS
] = { "bulk_trigger_pps", BLOBMSG_TYPE_INT32
},
159 [CL_CONFIG_PRIO_PKT_LEN
] = { "prio_max_avg_pkt_len", BLOBMSG_TYPE_INT32
},
160 [CL_CONFIG_INTERFACES
] = { "interfaces", BLOBMSG_TYPE_TABLE
},
161 [CL_CONFIG_DEVICES
] = { "devices", BLOBMSG_TYPE_TABLE
},
164 static int __set_dscp(uint8_t *dest
, struct blob_attr
*attr
, bool reset
)
174 dscp
= qosify_map_dscp_value(blobmsg_get_string(attr
));
184 qosify_ubus_config(struct ubus_context
*ctx
, struct ubus_object
*obj
,
185 struct ubus_request_data
*req
, const char *method
,
186 struct blob_attr
*msg
)
188 struct blob_attr
*tb
[__CL_CONFIG_MAX
];
189 struct blob_attr
*cur
;
194 blobmsg_parse(qosify_config_policy
, __CL_CONFIG_MAX
, tb
,
195 blobmsg_data(msg
), blobmsg_len(msg
));
197 if ((cur
= tb
[CL_CONFIG_RESET
]) != NULL
)
198 reset
= blobmsg_get_bool(cur
);
201 qosify_map_reset_config();
203 if ((cur
= tb
[CL_CONFIG_TIMEOUT
]) != NULL
)
204 qosify_map_timeout
= blobmsg_get_u32(cur
);
206 if ((cur
= tb
[CL_CONFIG_FILES
]) != NULL
&&
207 (ret
= qosify_ubus_set_files(cur
) != 0))
210 __set_dscp(&dscp
, tb
[CL_CONFIG_DSCP_UDP
], true);
212 qosify_map_set_dscp_default(CL_MAP_UDP_PORTS
, dscp
);
214 __set_dscp(&dscp
, tb
[CL_CONFIG_DSCP_TCP
], true);
216 qosify_map_set_dscp_default(CL_MAP_TCP_PORTS
, dscp
);
218 __set_dscp(&config
.dscp_prio
, tb
[CL_CONFIG_DSCP_PRIO
], reset
);
219 __set_dscp(&config
.dscp_bulk
, tb
[CL_CONFIG_DSCP_BULK
], reset
);
220 __set_dscp(&config
.dscp_icmp
, tb
[CL_CONFIG_DSCP_ICMP
], reset
);
222 if ((cur
= tb
[CL_CONFIG_BULK_TIMEOUT
]) != NULL
)
223 config
.bulk_trigger_timeout
= blobmsg_get_u32(cur
);
225 if ((cur
= tb
[CL_CONFIG_BULK_PPS
]) != NULL
)
226 config
.bulk_trigger_pps
= blobmsg_get_u32(cur
);
228 if ((cur
= tb
[CL_CONFIG_PRIO_PKT_LEN
]) != NULL
)
229 config
.prio_max_avg_pkt_len
= blobmsg_get_u32(cur
);
231 qosify_map_update_config();
233 qosify_iface_config_update(tb
[CL_CONFIG_INTERFACES
], tb
[CL_CONFIG_DEVICES
]);
235 qosify_iface_check();
242 qosify_ubus_dump(struct ubus_context
*ctx
, struct ubus_object
*obj
,
243 struct ubus_request_data
*req
, const char *method
,
244 struct blob_attr
*msg
)
246 blob_buf_init(&b
, 0);
248 ubus_send_reply(ctx
, req
, b
.head
);
255 qosify_ubus_status(struct ubus_context
*ctx
, struct ubus_object
*obj
,
256 struct ubus_request_data
*req
, const char *method
,
257 struct blob_attr
*msg
)
259 blob_buf_init(&b
, 0);
260 qosify_iface_status(&b
);
261 ubus_send_reply(ctx
, req
, b
.head
);
268 qosify_ubus_check_devices(struct ubus_context
*ctx
, struct ubus_object
*obj
,
269 struct ubus_request_data
*req
, const char *method
,
270 struct blob_attr
*msg
)
272 qosify_iface_check();
285 static const struct blobmsg_policy qosify_dns_policy
[__CL_DNS_HOST_MAX
] = {
286 [CL_DNS_HOST_NAME
] = { "name", BLOBMSG_TYPE_STRING
},
287 [CL_DNS_HOST_TYPE
] = { "type", BLOBMSG_TYPE_STRING
},
288 [CL_DNS_HOST_ADDR
] = { "address", BLOBMSG_TYPE_STRING
},
289 [CL_DNS_HOST_TTL
] = { "ttl", BLOBMSG_TYPE_INT32
},
293 qosify_ubus_add_dns_host(struct ubus_context
*ctx
, struct ubus_object
*obj
,
294 struct ubus_request_data
*req
, const char *method
,
295 struct blob_attr
*msg
)
297 struct blob_attr
*tb
[__CL_DNS_HOST_MAX
];
298 struct blob_attr
*cur
;
301 blobmsg_parse(qosify_dns_policy
, __CL_DNS_HOST_MAX
, tb
,
302 blobmsg_data(msg
), blobmsg_len(msg
));
304 if (!tb
[CL_DNS_HOST_NAME
] || !tb
[CL_DNS_HOST_TYPE
] ||
305 !tb
[CL_DNS_HOST_ADDR
])
306 return UBUS_STATUS_INVALID_ARGUMENT
;
308 if ((cur
= tb
[CL_DNS_HOST_TTL
]) != NULL
)
309 ttl
= blobmsg_get_u32(cur
);
311 if (qosify_map_add_dns_host(blobmsg_get_string(tb
[CL_DNS_HOST_NAME
]),
312 blobmsg_get_string(tb
[CL_DNS_HOST_ADDR
]),
313 blobmsg_get_string(tb
[CL_DNS_HOST_TYPE
]),
315 return UBUS_STATUS_INVALID_ARGUMENT
;
320 static const struct ubus_method qosify_methods
[] = {
321 UBUS_METHOD_NOARG("reload", qosify_ubus_reload
),
322 UBUS_METHOD("add", qosify_ubus_add
, qosify_add_policy
),
323 UBUS_METHOD_MASK("remove", qosify_ubus_add
, qosify_add_policy
,
324 ((1 << __CL_ADD_MAX
) - 1) & ~(1 << CL_ADD_DSCP
)),
325 UBUS_METHOD("config", qosify_ubus_config
, qosify_config_policy
),
326 UBUS_METHOD_NOARG("dump", qosify_ubus_dump
),
327 UBUS_METHOD_NOARG("status", qosify_ubus_status
),
328 UBUS_METHOD("add_dns_host", qosify_ubus_add_dns_host
, qosify_dns_policy
),
329 UBUS_METHOD_NOARG("check_devices", qosify_ubus_check_devices
),
332 static struct ubus_object_type qosify_object_type
=
333 UBUS_OBJECT_TYPE("qosify", qosify_methods
);
335 static struct ubus_object qosify_object
= {
337 .type
= &qosify_object_type
,
338 .methods
= qosify_methods
,
339 .n_methods
= ARRAY_SIZE(qosify_methods
),
343 ubus_connect_handler(struct ubus_context
*ctx
)
345 ubus_add_object(ctx
, &qosify_object
);
348 static struct ubus_auto_conn conn
;
350 int qosify_ubus_init(void)
352 conn
.cb
= ubus_connect_handler
;
353 ubus_auto_connect(&conn
);
358 void qosify_ubus_stop(void)
360 ubus_auto_shutdown(&conn
);
369 netifd_if_cb(struct ubus_request
*req
, int type
, struct blob_attr
*msg
)
371 struct iface_req
*ifr
= req
->priv
;
377 static const struct blobmsg_policy policy
[__IFS_ATTR_MAX
] = {
378 [IFS_ATTR_UP
] = { "up", BLOBMSG_TYPE_BOOL
},
379 [IFS_ATTR_DEV
] = { "l3_device", BLOBMSG_TYPE_STRING
},
381 struct blob_attr
*tb
[__IFS_ATTR_MAX
];
383 blobmsg_parse(policy
, __IFS_ATTR_MAX
, tb
, blobmsg_data(msg
), blobmsg_len(msg
));
385 if (!tb
[IFS_ATTR_UP
] || !tb
[IFS_ATTR_DEV
])
388 if (!blobmsg_get_bool(tb
[IFS_ATTR_UP
]))
391 snprintf(ifr
->name
, ifr
->len
, "%s", blobmsg_get_string(tb
[IFS_ATTR_DEV
]));
394 int qosify_ubus_check_interface(const char *name
, char *ifname
, int ifname_len
)
396 struct iface_req req
= { ifname
, ifname_len
};
397 char *obj_name
= "network.interface.";
400 #define PREFIX "network.interface."
401 obj_name
= alloca(sizeof(PREFIX
) + strlen(name
) + 1);
402 sprintf(obj_name
, PREFIX
"%s", name
);
407 if (ubus_lookup_id(&conn
.ctx
, obj_name
, &id
))
410 ubus_invoke(&conn
.ctx
, id
, "status", b
.head
, netifd_if_cb
, &req
, 1000);