Skip to content
Snippets Groups Projects
qosmngr.c 4.39 KiB
Newer Older
  • Learn to ignore specific revisions
  • /* SPDX-License-Identifier: GPL-2.0 */
    /*
     * qosmngr.c - main qosmngr's code
     *
     * Copyright (C) 2020 iopsys Software Solutions AB. All rights reserved.
     *
     * Author: Oskar Viljasaar <oskar.viljasaar@iopsys.eu>
     *
     * This program is free software; you can redistribute it and/or
     * modify it under the terms of the GNU General Public License
     * version 2 as published by the Free Software Foundation.
     *
     * This program is distributed in the hope that it will be useful, but
     * WITHOUT ANY WARRANTY; without even the implied warranty of
     * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
     * General Public License for more details.
     *
     * You should have received a copy of the GNU General Public License
     * along with this program; if not, write to the Free Software
     * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
     * 02110-1301 USA
     */
    
    #include <libubus.h>
    #include <uci.h>
    
    /* Needed to get the IFNAMSIZ define */
    #include <net/if.h>
    
    #include <qos.h>
    
    #include "qosmngr.h"
    
    /* Used as an internal value to query all the queues */
    #define QOS_QUEUE_ANY	-1
    
    enum {
          QOS_POLICY_IFNAME,
          QOS_POLICY_QID,
          QOS_POLICY_MAX,
          NUM_QOS_POLICY = QOS_POLICY_MAX,
    };
    
    static const struct blobmsg_policy get_status_policy[NUM_QOS_POLICY] = {
          [QOS_POLICY_IFNAME] = { .name = "ifname", .type = BLOBMSG_TYPE_STRING },
          [QOS_POLICY_QID] = { .name = "qid", .type = BLOBMSG_TYPE_INT32},
    };
    
    static const struct ubus_method qos_methods[] = {
            UBUS_METHOD("get_status", qosmngr_get_status, get_status_policy),
    };
    
    static struct ubus_object_type qos_object_type =
            UBUS_OBJECT_TYPE("qos", qos_methods);
    
    static struct ubus_object test_object = {
            .name = "qos",
            .type = &qos_object_type,
            .methods = qos_methods,
            .n_methods = ARRAY_SIZE(qos_methods),
    };
    
    int qosmngr_get_status(struct ubus_context *ctx, struct ubus_object *obj,
    	       struct ubus_request_data *req, const char *method,
    	       struct blob_attr *msg)
    {
    	struct blob_attr *tb[NUM_QOS_POLICY];
    	struct blob_buf b = {0};
    	struct qos_stats stats = {0};
    
    	char ifname[IFNAMSIZ] = {0};
    	int queue_id = QOS_QUEUE_ANY;
    
    	int i;
    	int ret;
    
    	/* These are for the blobbuf array elements */
    	void *d = NULL, *dd = NULL;
    
    	blobmsg_parse(get_status_policy, QOS_POLICY_MAX, tb, blob_data(msg),
    							blob_len(msg));
    
    
    	if (tb[QOS_POLICY_IFNAME]) {
    		strncpy(ifname, blobmsg_data(tb[QOS_POLICY_IFNAME]), sizeof(ifname)-1);
    	}
    
    	/* Parse optional arguments */
    	if (tb[QOS_POLICY_QID]) {
    		queue_id = blobmsg_get_u32(tb[QOS_POLICY_QID]);
    	}
    
    	/* Can't have a queue id specified without an interface */
    	if (tb[QOS_POLICY_QID] && !tb[QOS_POLICY_IFNAME]) {
    		return UBUS_STATUS_INVALID_ARGUMENT;
    	}
    
    	blob_buf_init(&b, 0);
    
    	d = blobmsg_open_array(&b, "queues");
    
    	if (queue_id == QOS_QUEUE_ANY) {
    		/* Should we replace this hardcoded limit of 'i' with something like
    		   libqos_get_no_queues(const char *iface), and deal with the number of queues
    		   internally library-side? */
    		for (i=0; i<8; i++) {
    
    			ret = qos_get_stats(ifname, i, &stats);
    			if (ret != 0) {
    				fprintf(stderr, "blob_get_status: ret %d\n", ret);
    				goto fail_get_status;
    			}
    
    			dd = blobmsg_open_table(&b, "");
    
    			blobmsg_add_string(&b, "iface", ifname);
    			blobmsg_add_u32(&b, "qid", i);
    			blobmsg_add_u32(&b, "tx_packets", stats.tx_packets);
    			blobmsg_add_u32(&b, "tx_bytes", stats.tx_bytes);
    			blobmsg_add_u32(&b, "tx_dropped_packets", stats.tx_dropped_packets);
    			blobmsg_add_u32(&b, "tx_dropped_bytes", stats.tx_dropped_bytes);
    
    			blobmsg_close_table(&b, dd);
    		}
    	} else {
    		ret = qos_get_stats(ifname, queue_id, &stats);
    		if (ret != 0) {
    			fprintf(stderr, "blob_get_status: ret %d\n", ret);
    			goto fail_get_status;
    		}
    
    		dd = blobmsg_open_table(&b, "");
    
    		blobmsg_add_string(&b, "iface", ifname);
    		blobmsg_add_u32(&b, "qid", queue_id);
    		blobmsg_add_u32(&b, "tx_packets", stats.tx_packets);
    		blobmsg_add_u32(&b, "tx_bytes", stats.tx_bytes);
    		blobmsg_add_u32(&b, "tx_dropped_packets", stats.tx_dropped_packets);
    		blobmsg_add_u32(&b, "tx_dropped_bytes", stats.tx_dropped_bytes);
    
    		blobmsg_close_table(&b, dd);
    	}
    
    	blobmsg_close_array(&b, d);
    
    	ubus_send_reply(ctx, req, b.head);
    
     fail_get_status:
    	blob_buf_free(&b);
    	return ret;
    }
    
    int qosmngr_publish_object(struct ubus_context *ctx)
    {
    	int ret;
    	ret = ubus_add_object(ctx, &test_object);
    	if (ret) {
    		fprintf(stderr, "Failed to add 'qos' ubus object: %s\n",
    			ubus_strerror(ret));
    	}
    
    	return ret;
    }