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
));
56 static const struct blobmsg_policy qosify_add_policy
[__CL_ADD_MAX
] = {
57 [CL_ADD_DSCP
] = { "dscp", BLOBMSG_TYPE_STRING
},
58 [CL_ADD_TIMEOUT
] = { "timeout", BLOBMSG_TYPE_INT32
},
59 [CL_ADD_IPV4
] = { "ipv4", BLOBMSG_TYPE_ARRAY
},
60 [CL_ADD_IPV6
] = { "ipv6", BLOBMSG_TYPE_ARRAY
},
61 [CL_ADD_TCP_PORT
] = { "tcp_port", BLOBMSG_TYPE_ARRAY
},
62 [CL_ADD_UDP_PORT
] = { "udp_port", BLOBMSG_TYPE_ARRAY
},
67 qosify_ubus_reload(struct ubus_context
*ctx
, struct ubus_object
*obj
,
68 struct ubus_request_data
*req
, const char *method
,
69 struct blob_attr
*msg
)
77 qosify_ubus_add(struct ubus_context
*ctx
, struct ubus_object
*obj
,
78 struct ubus_request_data
*req
, const char *method
,
79 struct blob_attr
*msg
)
81 int prev_timemout
= qosify_map_timeout
;
82 struct blob_attr
*tb
[__CL_ADD_MAX
];
83 struct blob_attr
*cur
;
87 blobmsg_parse(qosify_add_policy
, __CL_ADD_MAX
, tb
,
88 blobmsg_data(msg
), blobmsg_len(msg
));
90 if (!strcmp(method
, "add")) {
91 if ((cur
= tb
[CL_ADD_DSCP
]) != NULL
)
92 dscp
= qosify_map_dscp_value(blobmsg_get_string(cur
));
94 return UBUS_STATUS_INVALID_ARGUMENT
;
96 return UBUS_STATUS_INVALID_ARGUMENT
;
98 if ((cur
= tb
[CL_ADD_TIMEOUT
]) != NULL
)
99 qosify_map_timeout
= blobmsg_get_u32(cur
);
104 if ((cur
= tb
[CL_ADD_IPV4
]) != NULL
&&
105 (ret
= qosify_ubus_add_array(cur
, dscp
, CL_MAP_IPV4_ADDR
) != 0))
108 if ((cur
= tb
[CL_ADD_IPV6
]) != NULL
&&
109 (ret
= qosify_ubus_add_array(cur
, dscp
, CL_MAP_IPV6_ADDR
) != 0))
112 if ((cur
= tb
[CL_ADD_TCP_PORT
]) != NULL
&&
113 (ret
= qosify_ubus_add_array(cur
, dscp
, CL_MAP_TCP_PORTS
) != 0))
116 if ((cur
= tb
[CL_ADD_UDP_PORT
]) != NULL
&&
117 (ret
= qosify_ubus_add_array(cur
, dscp
, CL_MAP_UDP_PORTS
) != 0))
120 qosify_map_timeout
= prev_timemout
;
134 CL_CONFIG_BULK_TIMEOUT
,
136 CL_CONFIG_PRIO_PKT_LEN
,
137 CL_CONFIG_INTERFACES
,
142 static const struct blobmsg_policy qosify_config_policy
[__CL_CONFIG_MAX
] = {
143 [CL_CONFIG_RESET
] = { "reset", BLOBMSG_TYPE_BOOL
},
144 [CL_CONFIG_FILES
] = { "files", BLOBMSG_TYPE_ARRAY
},
145 [CL_CONFIG_TIMEOUT
] = { "timeout", BLOBMSG_TYPE_INT32
},
146 [CL_CONFIG_DSCP_UDP
] = { "dscp_default_udp", BLOBMSG_TYPE_STRING
},
147 [CL_CONFIG_DSCP_TCP
] = { "dscp_default_tcp", BLOBMSG_TYPE_STRING
},
148 [CL_CONFIG_DSCP_PRIO
] = { "dscp_prio", BLOBMSG_TYPE_STRING
},
149 [CL_CONFIG_DSCP_BULK
] = { "dscp_bulk", BLOBMSG_TYPE_STRING
},
150 [CL_CONFIG_DSCP_ICMP
] = { "dscp_icmp", BLOBMSG_TYPE_STRING
},
151 [CL_CONFIG_BULK_TIMEOUT
] = { "bulk_trigger_timeout", BLOBMSG_TYPE_INT32
},
152 [CL_CONFIG_BULK_PPS
] = { "bulk_trigger_pps", BLOBMSG_TYPE_INT32
},
153 [CL_CONFIG_PRIO_PKT_LEN
] = { "prio_max_avg_pkt_len", BLOBMSG_TYPE_INT32
},
154 [CL_CONFIG_INTERFACES
] = { "interfaces", BLOBMSG_TYPE_TABLE
},
155 [CL_CONFIG_DEVICES
] = { "devices", BLOBMSG_TYPE_TABLE
},
158 static int __set_dscp(uint8_t *dest
, struct blob_attr
*attr
, bool reset
)
168 dscp
= qosify_map_dscp_value(blobmsg_get_string(attr
));
178 qosify_ubus_config(struct ubus_context
*ctx
, struct ubus_object
*obj
,
179 struct ubus_request_data
*req
, const char *method
,
180 struct blob_attr
*msg
)
182 struct blob_attr
*tb
[__CL_CONFIG_MAX
];
183 struct blob_attr
*cur
;
188 blobmsg_parse(qosify_config_policy
, __CL_CONFIG_MAX
, tb
,
189 blobmsg_data(msg
), blobmsg_len(msg
));
191 if ((cur
= tb
[CL_CONFIG_RESET
]) != NULL
)
192 reset
= blobmsg_get_bool(cur
);
195 qosify_map_reset_config();
197 if ((cur
= tb
[CL_CONFIG_TIMEOUT
]) != NULL
)
198 qosify_map_timeout
= blobmsg_get_u32(cur
);
200 if ((cur
= tb
[CL_CONFIG_FILES
]) != NULL
&&
201 (ret
= qosify_ubus_set_files(cur
) != 0))
204 __set_dscp(&dscp
, tb
[CL_CONFIG_DSCP_UDP
], true);
206 qosify_map_set_dscp_default(CL_MAP_UDP_PORTS
, dscp
);
208 __set_dscp(&dscp
, tb
[CL_CONFIG_DSCP_TCP
], true);
210 qosify_map_set_dscp_default(CL_MAP_TCP_PORTS
, dscp
);
212 __set_dscp(&config
.dscp_prio
, tb
[CL_CONFIG_DSCP_PRIO
], reset
);
213 __set_dscp(&config
.dscp_bulk
, tb
[CL_CONFIG_DSCP_BULK
], reset
);
214 __set_dscp(&config
.dscp_icmp
, tb
[CL_CONFIG_DSCP_ICMP
], reset
);
216 if ((cur
= tb
[CL_CONFIG_BULK_TIMEOUT
]) != NULL
)
217 config
.bulk_trigger_timeout
= blobmsg_get_u32(cur
);
219 if ((cur
= tb
[CL_CONFIG_BULK_PPS
]) != NULL
)
220 config
.bulk_trigger_pps
= blobmsg_get_u32(cur
);
222 if ((cur
= tb
[CL_CONFIG_PRIO_PKT_LEN
]) != NULL
)
223 config
.prio_max_avg_pkt_len
= blobmsg_get_u32(cur
);
225 qosify_map_update_config();
227 qosify_iface_config_update(tb
[CL_CONFIG_INTERFACES
], tb
[CL_CONFIG_DEVICES
]);
229 qosify_iface_check();
236 qosify_ubus_dump(struct ubus_context
*ctx
, struct ubus_object
*obj
,
237 struct ubus_request_data
*req
, const char *method
,
238 struct blob_attr
*msg
)
240 blob_buf_init(&b
, 0);
242 ubus_send_reply(ctx
, req
, b
.head
);
249 qosify_ubus_status(struct ubus_context
*ctx
, struct ubus_object
*obj
,
250 struct ubus_request_data
*req
, const char *method
,
251 struct blob_attr
*msg
)
253 blob_buf_init(&b
, 0);
254 qosify_iface_status(&b
);
255 ubus_send_reply(ctx
, req
, b
.head
);
262 qosify_ubus_check_devices(struct ubus_context
*ctx
, struct ubus_object
*obj
,
263 struct ubus_request_data
*req
, const char *method
,
264 struct blob_attr
*msg
)
266 qosify_iface_check();
272 static const struct ubus_method qosify_methods
[] = {
273 UBUS_METHOD_NOARG("reload", qosify_ubus_reload
),
274 UBUS_METHOD("add", qosify_ubus_add
, qosify_add_policy
),
275 UBUS_METHOD_MASK("remove", qosify_ubus_add
, qosify_add_policy
,
276 ((1 << __CL_ADD_MAX
) - 1) & ~(1 << CL_ADD_DSCP
)),
277 UBUS_METHOD("config", qosify_ubus_config
, qosify_config_policy
),
278 UBUS_METHOD_NOARG("dump", qosify_ubus_dump
),
279 UBUS_METHOD_NOARG("status", qosify_ubus_status
),
280 UBUS_METHOD_NOARG("check_devices", qosify_ubus_check_devices
),
283 static struct ubus_object_type qosify_object_type
=
284 UBUS_OBJECT_TYPE("qosify", qosify_methods
);
286 static struct ubus_object qosify_object
= {
288 .type
= &qosify_object_type
,
289 .methods
= qosify_methods
,
290 .n_methods
= ARRAY_SIZE(qosify_methods
),
294 ubus_connect_handler(struct ubus_context
*ctx
)
296 ubus_add_object(ctx
, &qosify_object
);
299 static struct ubus_auto_conn conn
;
301 int qosify_ubus_init(void)
303 conn
.cb
= ubus_connect_handler
;
304 ubus_auto_connect(&conn
);
309 void qosify_ubus_stop(void)
311 ubus_auto_shutdown(&conn
);
320 netifd_if_cb(struct ubus_request
*req
, int type
, struct blob_attr
*msg
)
322 struct iface_req
*ifr
= req
->priv
;
328 static const struct blobmsg_policy policy
[__IFS_ATTR_MAX
] = {
329 [IFS_ATTR_UP
] = { "up", BLOBMSG_TYPE_BOOL
},
330 [IFS_ATTR_DEV
] = { "l3_device", BLOBMSG_TYPE_STRING
},
332 struct blob_attr
*tb
[__IFS_ATTR_MAX
];
334 blobmsg_parse(policy
, __IFS_ATTR_MAX
, tb
, blobmsg_data(msg
), blobmsg_len(msg
));
336 if (!tb
[IFS_ATTR_UP
] || !tb
[IFS_ATTR_DEV
])
339 if (!blobmsg_get_bool(tb
[IFS_ATTR_UP
]))
342 snprintf(ifr
->name
, ifr
->len
, "%s", blobmsg_get_string(tb
[IFS_ATTR_DEV
]));
345 int qosify_ubus_check_interface(const char *name
, char *ifname
, int ifname_len
)
347 struct iface_req req
= { ifname
, ifname_len
};
348 char *obj_name
= "network.interface.";
351 #define PREFIX "network.interface."
352 obj_name
= alloca(sizeof(PREFIX
) + strlen(name
) + 1);
353 sprintf(obj_name
, PREFIX
"%s", name
);
358 if (ubus_lookup_id(&conn
.ctx
, obj_name
, &id
))
361 ubus_invoke(&conn
.ctx
, id
, "status", b
.head
, netifd_if_cb
, &req
, 1000);