* [PATCH RESEND] net: qrtr: support qrtr service and lookup route
@ 2020-04-08 10:46 Wang Wenhu
2020-04-08 21:33 ` David Miller
` (2 more replies)
0 siblings, 3 replies; 8+ messages in thread
From: Wang Wenhu @ 2020-04-08 10:46 UTC (permalink / raw)
To: akpm, David S. Miller, Jakub Kicinski, Greg Kroah-Hartman,
Wang Wenhu, Thomas Gleixner, Bjorn Andersson, Nicholas Mc Guire,
Allison Randal, Johannes Berg, Arnd Bergmann, Carl Huang,
linux-kernel, netdev
Cc: kernel
QSR implements maintenance of qrtr services and lookups. It would
be helpful for developers to work with QRTR without the none-opensource
user-space implementation part of IPC Router.
As we know, the extremely important point of IPC Router is the support
of services form different nodes. But QRTR was pushed into mainline
without route process support of services, and the router port process
is implemented in user-space as none-opensource codes, which is an
great unconvenience for developers.
QSR also implements a interface via chardev and a set of sysfs class
files for the communication and debugging in user-space. We can get
service and lookup entries conveniently via sysfs file in /sys/class/qsr/.
Currently add-server, del-server, add-lookup and del-lookup control
packatets are processed and enhancements could be taken easily upon
currently implementation.
Signed-off-by: Wang Wenhu <wenhu.wang@vivo.com>
---
Changelog:
This is a resent, but the first normal version of QSR support.
The former one sent out earlier contains only the patch of coding
style modification of qsr.c.
Please do not be confused and take this patch as the NORMAL commit of QSR.
---
net/qrtr/Kconfig | 8 +
net/qrtr/Makefile | 2 +
net/qrtr/qrtr.c | 5 +
net/qrtr/qrtr.h | 2 +
net/qrtr/qsr.c | 622 ++++++++++++++++++++++++++++++++++++++++++++++
5 files changed, 639 insertions(+)
create mode 100644 net/qrtr/qsr.c
diff --git a/net/qrtr/Kconfig b/net/qrtr/Kconfig
index 63f89cc6e82c..d2ce8fb57278 100644
--- a/net/qrtr/Kconfig
+++ b/net/qrtr/Kconfig
@@ -29,4 +29,12 @@ config QRTR_TUN
implement endpoints of QRTR, for purpose of tunneling data to other
hosts or testing purposes.
+config QSR
+ tristate "QRTR Service Router"
+ help
+ Say Y here to enable the kernel QRTR Service Router module.
+ QSR support route processes of QRTR services and lookups. It would be
+ helpful when develop with QRTR without user-space implementation of
+ IPC Router support.
+
endif # QRTR
diff --git a/net/qrtr/Makefile b/net/qrtr/Makefile
index 1c6d6c120fb7..3882beaead29 100644
--- a/net/qrtr/Makefile
+++ b/net/qrtr/Makefile
@@ -5,3 +5,5 @@ obj-$(CONFIG_QRTR_SMD) += qrtr-smd.o
qrtr-smd-y := smd.o
obj-$(CONFIG_QRTR_TUN) += qrtr-tun.o
qrtr-tun-y := tun.o
+obj-$(CONFIG_QSR) += qrtr-svc-router.o
+qrtr-svc-router-y := qsr.o
diff --git a/net/qrtr/qrtr.c b/net/qrtr/qrtr.c
index 5a8e42ad1504..267f7d6c746f 100644
--- a/net/qrtr/qrtr.c
+++ b/net/qrtr/qrtr.c
@@ -158,6 +158,11 @@ static int qrtr_bcast_enqueue(struct qrtr_node *node, struct sk_buff *skb,
static struct qrtr_sock *qrtr_port_lookup(int port);
static void qrtr_port_put(struct qrtr_sock *ipc);
+unsigned int get_qrtr_local_nid(void)
+{
+ return qrtr_local_nid;
+}
+
/* Release node resources and free the node.
*
* Do not call directly, use qrtr_node_release. To be used with
diff --git a/net/qrtr/qrtr.h b/net/qrtr/qrtr.h
index b81e6953c04b..872d98fd36c6 100644
--- a/net/qrtr/qrtr.h
+++ b/net/qrtr/qrtr.h
@@ -29,4 +29,6 @@ void qrtr_endpoint_unregister(struct qrtr_endpoint *ep);
int qrtr_endpoint_post(struct qrtr_endpoint *ep, const void *data, size_t len);
+unsigned int get_qrtr_local_nid(void);
+
#endif
diff --git a/net/qrtr/qsr.c b/net/qrtr/qsr.c
new file mode 100644
index 000000000000..906f5903ebad
--- /dev/null
+++ b/net/qrtr/qsr.c
@@ -0,0 +1,622 @@
+// SPDX-License-Identifier: GPL-2.0
+
+/*
+ * Copyright (C) 2020 Vivo Communication Technology Co. Ltd.
+ * Copyright (C) 2020 Wang Wenhu <wenhu.wang@vivo.com>
+ *
+ * The QRTR Service Route module aims at providing maintenance
+ * and route processes for qrtr service and lookup requests in
+ * kernel. Also, it provides sysfs class interface to expose
+ * the status of qrtr services and lookups. More could be done
+ * through the character device /dev/qsr in user-space.
+ *
+ * Currently, only server add, server delete, lookup add and
+ * lookup delete requests are processed.
+ */
+
+#include <linux/module.h>
+#include <linux/skbuff.h>
+#include <linux/mutex.h>
+#include <linux/device.h>
+#include <linux/string.h>
+#include <linux/kobject.h>
+#include <linux/cdev.h>
+#include <linux/qrtr.h>
+#include <net/sock.h>
+
+#include "qrtr.h"
+
+#define QSR_NAME "qsr"
+
+/**
+ * struct qsr_info - qrtr service route request information
+ * @service: service identity
+ * @instance: service instance
+ * @server: server address
+ * @client: client address
+ * @node: qrtr node of server or client
+ * @port: qrtr port of server or client
+ *
+ * When a control packet of new server request is received, the server
+ * field should be reference for the server node address. For the opposite
+ * situation, the client field should be referenced within a lookup request.
+ */
+struct qsr_info {
+ __le32 service;
+ __le32 instance;
+
+ union {
+ struct {
+ __le32 node;
+ __le32 port;
+ } server;
+
+ struct {
+ __le32 node;
+ __le32 port;
+ } client;
+ };
+
+ struct list_head list;
+};
+
+/**
+ * struct qsr - qrtr service route device structure
+ * @dev: character device for user-space communication
+ * @sk: socket to process messages
+ * @sq: socket address to be binded
+ * @ops: callbacks of different control package types
+ * @qsr_lock: data buffer lock
+ * @recv_buf: receive buffer
+ * @recv_buf_size: receive buffer size
+ * @wq: workqueue for message process worker
+ * @work: work route to process queued messages
+ * @lookups: pending lookup requests
+ * @services: servers list to provide different kind of services
+ */
+struct qsr {
+ struct device dev;
+ struct socket *sk;
+ struct sockaddr_qrtr sq;
+ struct qsr_ops *ops;
+
+ struct mutex qsr_lock;
+ void *recv_buf;
+ size_t recv_buf_size;
+
+ struct workqueue_struct *wq;
+ struct work_struct work;
+
+ struct list_head lookups;
+ struct list_head services;
+};
+
+struct qsr_ops {
+ int (*new_server)(struct qsr_info *svc);
+ int (*new_lookup)(struct qsr_info *svc, u32 node, u32 port);
+};
+
+static int qsr_major;
+static struct cdev *qsr_cdev;
+static struct qsr *qsr;
+
+static int qsr_new_server(struct qsr_info *new)
+{
+ struct qsr_info *lookup;
+ struct qsr_ops *ops = qsr->ops;
+ int ret;
+
+ if (!ops->new_lookup)
+ return 0;
+
+ list_for_each_entry(lookup, &qsr->lookups, list) {
+ if (lookup->service == new->service &&
+ lookup->instance == new->instance) {
+ ret = ops->new_lookup(new,
+ lookup->client.node,
+ lookup->client.port);
+ if (ret < 0)
+ pr_err("Error to notice client of new server, %d\n", ret);
+ else
+ list_del(&lookup->list);
+ return 0;
+ }
+ }
+
+ return 0;
+}
+
+static int qsr_new_lookup(struct qsr_info *svc, u32 node, u32 port)
+{
+ struct qrtr_ctrl_pkt pkt;
+ struct sockaddr_qrtr sq;
+ struct msghdr msg = { };
+ struct kvec iv = { &pkt, sizeof(pkt) };
+ int ret = 0;
+
+ memset(&pkt, 0, sizeof(pkt));
+ pkt.cmd = cpu_to_le32(QRTR_TYPE_NEW_SERVER);
+ pkt.server.service = cpu_to_le32(svc->service);
+ pkt.server.instance = cpu_to_le32(svc->instance);
+ pkt.server.node = cpu_to_le32(svc->server.node);
+ pkt.server.port = cpu_to_le32(svc->server.port);
+
+ sq.sq_family = AF_QIPCRTR;
+ sq.sq_node = node;
+ sq.sq_port = port;
+
+ msg.msg_name = &sq;
+ msg.msg_namelen = sizeof(sq);
+
+ mutex_lock(&qsr->qsr_lock);
+ if (qsr->sk) {
+ ret = kernel_sendmsg(qsr->sk, &msg, &iv, 1, sizeof(pkt));
+ if (ret < 0)
+ pr_err("Error to send server info to client, %d\n", ret);
+ }
+ mutex_unlock(&qsr->qsr_lock);
+
+ return ret;
+}
+
+static void qsr_recv_new_server(u32 service,
+ u32 instance,
+ u32 node,
+ u32 port)
+{
+ struct qsr_ops *ops = qsr->ops;
+ struct qsr_info *svc, *temp;
+ int ret;
+
+ if (!ops->new_server)
+ return;
+
+ if (!node && !port)
+ return;
+
+ list_for_each_entry(temp, &qsr->services, list) {
+ if (temp->service == service && temp->instance == instance) {
+ pr_err("Error server exists, service:0x%x instance:0x%x",
+ service, instance);
+ return;
+ }
+ }
+
+ svc = kzalloc(sizeof(*svc), GFP_KERNEL);
+ if (!svc)
+ return;
+
+ svc->service = service;
+ svc->instance = instance;
+ svc->server.node = node;
+ svc->server.port = port;
+
+ ret = ops->new_server(svc);
+ if (ret < 0)
+ kfree(svc);
+ else
+ list_add(&svc->list, &qsr->services);
+}
+
+static void qsr_recv_del_server(u32 service, u32 instance)
+{
+ struct qsr_info *svc;
+
+ list_for_each_entry(svc, &qsr->lookups, list) {
+ if (svc->service == service && svc->instance == instance) {
+ list_del(&svc->list);
+ return;
+ }
+ }
+}
+
+static void qsr_recv_new_lookup(u32 service,
+ u32 instance,
+ u32 node,
+ u32 port)
+{
+ struct qsr_ops *ops = qsr->ops;
+ struct qsr_info *svc, *temp;
+ int ret;
+
+ if (!ops->new_lookup)
+ return;
+
+ if (!node && !port)
+ return;
+
+ list_for_each_entry(temp, &qsr->lookups, list) {
+ if (temp->service == service &&
+ temp->instance == instance &&
+ temp->client.node == node &&
+ temp->client.port == port) {
+ pr_err("Error lookup exists, service:0x%x instance:0x%x node:%d port:%d",
+ service, instance, node, port);
+ return;
+ }
+ }
+
+ list_for_each_entry(svc, &qsr->services, list) {
+ if (svc->service == service && svc->instance == instance) {
+ ret = ops->new_lookup(svc, node, port);
+ if (ret < 0)
+ pr_err("Error to send server info to client, %d", ret);
+ return;
+ }
+ }
+
+ /* Server does not exist.
+ * Record the lookup information and add it to the pending list.
+ */
+
+ svc = kzalloc(sizeof(*svc), GFP_KERNEL);
+ if (!svc)
+ return;
+
+ svc->service = service;
+ svc->instance = instance;
+ svc->client.node = node;
+ svc->client.port = port;
+
+ list_add(&svc->list, &qsr->lookups);
+}
+
+static void qsr_recv_del_lookup(u32 service,
+ u32 instance,
+ u32 node,
+ u32 port)
+{
+ struct qsr_info *lookup;
+
+ if (!node && !port)
+ return;
+
+ list_for_each_entry(lookup, &qsr->lookups, list) {
+ if (lookup->service == service &&
+ lookup->instance == instance &&
+ lookup->client.node == node &&
+ lookup->client.port == port) {
+ list_del(&lookup->list);
+ return;
+ }
+ }
+}
+
+static void qsr_recv_ctrl_pkt(struct sockaddr_qrtr *sq,
+ const void *buf,
+ size_t len)
+{
+ const struct qrtr_ctrl_pkt *pkt = buf;
+
+ if (len < sizeof(struct qrtr_ctrl_pkt)) {
+ pr_debug("ignoring short control packet\n");
+ return;
+ }
+
+ switch (le32_to_cpu(pkt->cmd)) {
+ case QRTR_TYPE_NEW_SERVER:
+ qsr_recv_new_server(le32_to_cpu(pkt->server.service),
+ le32_to_cpu(pkt->server.instance),
+ le32_to_cpu(pkt->server.node),
+ le32_to_cpu(pkt->server.port));
+ break;
+
+ case QRTR_TYPE_NEW_LOOKUP:
+ qsr_recv_new_lookup(le32_to_cpu(pkt->server.service),
+ le32_to_cpu(pkt->server.instance),
+ sq->sq_node,
+ sq->sq_port);
+ break;
+
+ case QRTR_TYPE_DEL_SERVER:
+ qsr_recv_del_server(le32_to_cpu(pkt->server.service),
+ le32_to_cpu(pkt->server.instance));
+ break;
+
+ case QRTR_TYPE_DEL_LOOKUP:
+ qsr_recv_del_lookup(le32_to_cpu(pkt->server.service),
+ le32_to_cpu(pkt->server.instance),
+ sq->sq_node,
+ sq->sq_port);
+ break;
+ }
+}
+
+static void qsr_recv_work(struct work_struct *work)
+{
+ struct sockaddr_qrtr sq;
+ struct msghdr msg = { .msg_name = &sq, .msg_namelen = sizeof(sq) };
+ struct kvec iv;
+ ssize_t msglen;
+
+ for (;;) {
+ iv.iov_base = qsr->recv_buf;
+ iv.iov_len = qsr->recv_buf_size;
+
+ mutex_lock(&qsr->qsr_lock);
+ if (qsr->sk)
+ msglen = kernel_recvmsg(qsr->sk, &msg, &iv, 1,
+ iv.iov_len, MSG_DONTWAIT);
+ else
+ msglen = -EPIPE;
+ mutex_unlock(&qsr->qsr_lock);
+
+ if (msglen == -EAGAIN)
+ break;
+
+ if (msglen < 0) {
+ pr_err("qmi recvmsg failed: %zd\n", msglen);
+ break;
+ }
+
+ qsr_recv_ctrl_pkt(&sq, qsr->recv_buf, msglen);
+ }
+}
+
+static void qsr_data_ready(struct sock *sk)
+{
+ read_lock_bh(&sk->sk_callback_lock);
+ queue_work(qsr->wq, &qsr->work);
+ read_unlock_bh(&sk->sk_callback_lock);
+}
+
+static ssize_t name_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ int ret;
+
+ mutex_lock(&qsr->qsr_lock);
+ ret = sprintf(buf, "%s\n", QSR_NAME);
+ mutex_unlock(&qsr->qsr_lock);
+
+ return ret;
+}
+static DEVICE_ATTR_RO(name);
+
+static ssize_t lookups_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct qsr_info *lookup;
+ int ret = 0;
+
+ mutex_lock(&qsr->qsr_lock);
+ list_for_each_entry(lookup, &qsr->lookups, list) {
+ ret += sprintf(buf, "service:0x%04x instance:0x%04x node:%04d port:%04d\n",
+ lookup->service,
+ lookup->instance,
+ lookup->server.node,
+ lookup->server.port);
+ }
+ mutex_unlock(&qsr->qsr_lock);
+
+ return ret;
+}
+static DEVICE_ATTR_RO(lookups);
+
+static ssize_t services_show(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct qsr_info *svc;
+ int ret = 0;
+
+ mutex_lock(&qsr->qsr_lock);
+ list_for_each_entry(svc, &qsr->services, list) {
+ ret += sprintf(buf, "service:0x%04x instance:0x%04x node:%04d port:%04d\n",
+ svc->service,
+ svc->instance,
+ svc->server.node,
+ svc->server.port);
+ }
+ mutex_unlock(&qsr->qsr_lock);
+
+ return ret;
+}
+static DEVICE_ATTR_RO(services);
+
+static struct attribute *qsr_attrs[] = {
+ &dev_attr_name.attr,
+ &dev_attr_lookups.attr,
+ &dev_attr_services.attr,
+ NULL,
+};
+ATTRIBUTE_GROUPS(qsr);
+
+/* Interface class infrastructure. */
+static struct class qsr_class = {
+ .name = QSR_NAME,
+ .dev_groups = qsr_groups,
+};
+
+static int qsr_dev_create(void)
+{
+ int ret = -ENOMEM;
+
+ qsr = kzalloc(sizeof(*qsr), GFP_KERNEL);
+ if (!qsr)
+ goto out;
+
+ INIT_LIST_HEAD(&qsr->lookups);
+ INIT_LIST_HEAD(&qsr->services);
+
+ INIT_WORK(&qsr->work, qsr_recv_work);
+
+ qsr->recv_buf_size = sizeof(struct qrtr_ctrl_pkt);
+ qsr->recv_buf = kzalloc(qsr->recv_buf_size, GFP_KERNEL);
+ if (!qsr->recv_buf)
+ goto out_qsr_free;
+
+ qsr->wq = alloc_workqueue("qsr_wq", WQ_UNBOUND, 1);
+ if (!qsr->wq)
+ goto out_recv_buf_free;
+
+ device_initialize(&qsr->dev);
+ qsr->dev.devt = MKDEV(qsr_major, 0);
+ qsr->dev.class = &qsr_class;
+ dev_set_drvdata(&qsr->dev, qsr);
+
+ ret = dev_set_name(&qsr->dev, QSR_NAME);
+ if (ret) {
+ pr_err("device name %s set failed, %d", QSR_NAME, ret);
+ goto out_recv_buf_free;
+ }
+
+ mutex_init(&qsr->qsr_lock);
+
+ ret = device_add(&qsr->dev);
+ if (ret)
+ goto out_wq_destroy;
+
+ return ret;
+
+out_wq_destroy:
+ destroy_workqueue(qsr->wq);
+out_recv_buf_free:
+ kfree(qsr->recv_buf);
+out_qsr_free:
+ kfree(qsr);
+out:
+ return ret;
+}
+
+struct qsr_ops qsr_handle_ops = {
+ .new_server = qsr_new_server,
+ .new_lookup = qsr_new_lookup,
+};
+
+static struct socket *qsr_sock_create(void)
+{
+ struct socket *sock;
+ struct sockaddr addr;
+ int ret;
+
+ ret = sock_create_kern(&init_net, AF_QIPCRTR, SOCK_DGRAM,
+ PF_QIPCRTR, &sock);
+
+ if (ret < 0)
+ return ERR_PTR(ret);
+
+ qsr->sq.sq_family = AF_QIPCRTR;
+ qsr->sq.sq_node = get_qrtr_local_nid();
+ qsr->sq.sq_port = QRTR_PORT_CTRL;
+ qsr->ops = &qsr_handle_ops;
+
+ if (sock->ops->bind) {
+ memcpy(&addr, &qsr->sq, sizeof(qsr->sq));
+ ret = sock->ops->bind(sock, &addr, sizeof(addr));
+ if (ret) {
+ pr_err("Failed to bind socket address node:0x%x port:0x%x.\n",
+ qsr->sq.sq_node, qsr->sq.sq_port);
+ goto err_bind;
+ }
+ pr_debug("qsr router port binded successfully.\n");
+ }
+
+ sock->sk->sk_user_data = qsr;
+ sock->sk->sk_data_ready = qsr_data_ready;
+ sock->sk->sk_error_report = qsr_data_ready;
+ sock->sk->sk_sndtimeo = HZ * 10;
+
+ return sock;
+
+err_bind:
+ sock_release(sock);
+ return NULL;
+}
+
+static int qsr_release(void)
+{
+ sock_release(qsr->sk);
+
+ kfree(qsr->recv_buf);
+
+ destroy_workqueue(qsr->wq);
+
+ kfree(qsr);
+
+ return 0;
+}
+
+static const struct file_operations qsr_fops = {
+ .owner = THIS_MODULE,
+};
+
+static int __init qsr_init(void)
+{
+ int ret;
+ static const char name[] = QSR_NAME;
+ struct cdev *cdev = NULL;
+ dev_t rtdev;
+
+ /* 1. Allocate character device region. */
+ ret = alloc_chrdev_region(&rtdev, 0, 1, name);
+ if (ret) {
+ pr_err("failed to alloc chardev region\n");
+ goto out;
+ }
+
+ /* 2. Allocate, initiate and add cdev. */
+ ret = -ENOMEM;
+ cdev = cdev_alloc();
+ if (!cdev) {
+ pr_err("failed to alloc cdev\n");
+ goto out_unregister;
+ }
+
+ cdev->owner = THIS_MODULE;
+ cdev->ops = &qsr_fops;
+ kobject_set_name(&cdev->kobj, "%s", name);
+
+ ret = cdev_add(cdev, rtdev, 1);
+ if (ret)
+ goto out_put;
+
+ qsr_major = MAJOR(rtdev);
+ qsr_cdev = cdev;
+
+ /* 3. Register class. */
+ ret = class_register(&qsr_class);
+ if (ret) {
+ pr_err("class_register failed for qrtr route\n");
+ goto out_cdev_del;
+ }
+
+ /* 4. Create a qsr device. */
+ if (qsr_dev_create())
+ goto out_unregister_class;
+
+ /* 5. Create a qrtr socket and bind it to Router port. */
+ qsr->sk = qsr_sock_create();
+ if (!qsr->sk)
+ goto out_qsr_dev_del;
+
+ return 0;
+
+out_qsr_dev_del:
+ kfree(qsr);
+out_unregister_class:
+ class_unregister(&qsr_class);
+out_cdev_del:
+ cdev_del(qsr_cdev);
+out_put:
+ kobject_put(&cdev->kobj);
+out_unregister:
+ unregister_chrdev_region(rtdev, 1);
+out:
+ return ret;
+}
+subsys_initcall(qsr_init);
+
+static void __exit qsr_exit(void)
+{
+ qsr_release();
+ unregister_chrdev_region(MKDEV(qsr_major, 0), 1);
+ cdev_del(qsr_cdev);
+ class_unregister(&qsr_class);
+}
+module_exit(qsr_exit);
+
+MODULE_AUTHOR("Wang Wenhu");
+MODULE_ALIAS("QRTR:" QSR_NAME);
+MODULE_DESCRIPTION("Qualcomm IPC Router Service Route Support");
+MODULE_LICENSE("GPL v2");
--
2.17.1
^ permalink raw reply related [flat|nested] 8+ messages in thread
* Re: [PATCH RESEND] net: qrtr: support qrtr service and lookup route
2020-04-08 10:46 [PATCH RESEND] net: qrtr: support qrtr service and lookup route Wang Wenhu
@ 2020-04-08 21:33 ` David Miller
2020-04-09 4:18 ` 王文虎
2020-04-09 4:24 ` kbuild test robot
2020-04-09 19:38 ` Bjorn Andersson
2 siblings, 1 reply; 8+ messages in thread
From: David Miller @ 2020-04-08 21:33 UTC (permalink / raw)
To: wenhu.wang
Cc: akpm, kuba, gregkh, tglx, bjorn.andersson, hofrat, allison,
johannes.berg, arnd, cjhuang, linux-kernel, netdev, kernel
From: Wang Wenhu <wenhu.wang@vivo.com>
Date: Wed, 8 Apr 2020 03:46:35 -0700
> QSR implements maintenance of qrtr services and lookups. It would
> be helpful for developers to work with QRTR without the none-opensource
> user-space implementation part of IPC Router.
>
> As we know, the extremely important point of IPC Router is the support
> of services form different nodes. But QRTR was pushed into mainline
> without route process support of services, and the router port process
> is implemented in user-space as none-opensource codes, which is an
> great unconvenience for developers.
>
> QSR also implements a interface via chardev and a set of sysfs class
> files for the communication and debugging in user-space. We can get
> service and lookup entries conveniently via sysfs file in /sys/class/qsr/.
> Currently add-server, del-server, add-lookup and del-lookup control
> packatets are processed and enhancements could be taken easily upon
> currently implementation.
>
> Signed-off-by: Wang Wenhu <wenhu.wang@vivo.com>
New features are only appropriate for net-next which is closed right now.
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [PATCH RESEND] net: qrtr: support qrtr service and lookup route
@ 2020-04-09 2:14 kbuild test robot
0 siblings, 0 replies; 8+ messages in thread
From: kbuild test robot @ 2020-04-09 2:14 UTC (permalink / raw)
To: kbuild
[-- Attachment #1: Type: text/plain, Size: 12216 bytes --]
CC: kbuild-all(a)lists.01.org
In-Reply-To: <20200408104833.6880-1-wenhu.wang@vivo.com>
References: <20200408104833.6880-1-wenhu.wang@vivo.com>
TO: Wang Wenhu <wenhu.wang@vivo.com>
CC: kernel(a)vivo.com
Hi Wang,
Thank you for the patch! Perhaps something to improve:
[auto build test WARNING on v5.6]
[cannot apply to net-next/master net/master linus/master sparc-next/master next-20200408]
[if your patch is applied to the wrong git tree, please drop us a note to help
improve the system. BTW, we also suggest to use '--base' option to specify the
base tree in git format-patch, please see https://stackoverflow.com/a/37406982]
url: https://github.com/0day-ci/linux/commits/Wang-Wenhu/net-qrtr-support-qrtr-service-and-lookup-route/20200408-234613
base: 7111951b8d4973bda27ff663f2cf18b663d15b48
reproduce:
# apt-get install sparse
# sparse version:
make ARCH=x86_64 allmodconfig
make C=1 CF='-fdiagnostic-prefix -D__CHECK_ENDIAN__'
:::::: branch date: 10 hours ago
:::::: commit date: 10 hours ago
If you fix the issue, kindly add following tag as appropriate
Reported-by: kbuild test robot <lkp@intel.com>
sparse warnings: (new ones prefixed by >>)
net/qrtr/qsr.c:116:71: sparse: warning: incorrect type in argument 2 (different base types)
>> net/qrtr/qsr.c:116:71: sparse: expected unsigned int [usertype] node
>> net/qrtr/qsr.c:116:71: sparse: got restricted __le32 [usertype] node
net/qrtr/qsr.c:117:71: sparse: warning: incorrect type in argument 3 (different base types)
>> net/qrtr/qsr.c:117:71: sparse: expected unsigned int [usertype] port
>> net/qrtr/qsr.c:117:71: sparse: got restricted __le32 [usertype] port
net/qrtr/qsr.c:139:30: sparse: warning: cast from restricted __le32
net/qrtr/qsr.c:140:31: sparse: warning: cast from restricted __le32
net/qrtr/qsr.c:141:27: sparse: warning: cast from restricted __le32
net/qrtr/qsr.c:142:27: sparse: warning: cast from restricted __le32
net/qrtr/qsr.c:178:25: sparse: warning: restricted __le32 degrades to integer
net/qrtr/qsr.c:178:53: sparse: warning: restricted __le32 degrades to integer
net/qrtr/qsr.c:189:22: sparse: warning: incorrect type in assignment (different base types)
>> net/qrtr/qsr.c:189:22: sparse: expected restricted __le32 [usertype] service
>> net/qrtr/qsr.c:189:22: sparse: got unsigned int [usertype] service
net/qrtr/qsr.c:190:23: sparse: warning: incorrect type in assignment (different base types)
>> net/qrtr/qsr.c:190:23: sparse: expected restricted __le32 [usertype] instance
>> net/qrtr/qsr.c:190:23: sparse: got unsigned int [usertype] instance
net/qrtr/qsr.c:191:26: sparse: warning: incorrect type in assignment (different base types)
>> net/qrtr/qsr.c:191:26: sparse: expected restricted __le32 [usertype] node
>> net/qrtr/qsr.c:191:26: sparse: got unsigned int [usertype] node
net/qrtr/qsr.c:192:26: sparse: warning: incorrect type in assignment (different base types)
>> net/qrtr/qsr.c:192:26: sparse: expected restricted __le32 [usertype] port
>> net/qrtr/qsr.c:192:26: sparse: got unsigned int [usertype] port
net/qrtr/qsr.c:206:24: sparse: warning: restricted __le32 degrades to integer
net/qrtr/qsr.c:206:51: sparse: warning: restricted __le32 degrades to integer
net/qrtr/qsr.c:229:25: sparse: warning: restricted __le32 degrades to integer
net/qrtr/qsr.c:230:25: sparse: warning: restricted __le32 degrades to integer
net/qrtr/qsr.c:231:33: sparse: warning: restricted __le32 degrades to integer
net/qrtr/qsr.c:232:33: sparse: warning: restricted __le32 degrades to integer
net/qrtr/qsr.c:240:24: sparse: warning: restricted __le32 degrades to integer
net/qrtr/qsr.c:240:51: sparse: warning: restricted __le32 degrades to integer
net/qrtr/qsr.c:256:22: sparse: warning: incorrect type in assignment (different base types)
net/qrtr/qsr.c:256:22: sparse: expected restricted __le32 [usertype] service
net/qrtr/qsr.c:256:22: sparse: got unsigned int [usertype] service
net/qrtr/qsr.c:257:23: sparse: warning: incorrect type in assignment (different base types)
net/qrtr/qsr.c:257:23: sparse: expected restricted __le32 [usertype] instance
net/qrtr/qsr.c:257:23: sparse: got unsigned int [usertype] instance
net/qrtr/qsr.c:258:26: sparse: warning: incorrect type in assignment (different base types)
net/qrtr/qsr.c:258:26: sparse: expected restricted __le32 [usertype] node
net/qrtr/qsr.c:258:26: sparse: got unsigned int [usertype] node
net/qrtr/qsr.c:259:26: sparse: warning: incorrect type in assignment (different base types)
net/qrtr/qsr.c:259:26: sparse: expected restricted __le32 [usertype] port
net/qrtr/qsr.c:259:26: sparse: got unsigned int [usertype] port
net/qrtr/qsr.c:275:27: sparse: warning: restricted __le32 degrades to integer
net/qrtr/qsr.c:276:27: sparse: warning: restricted __le32 degrades to integer
net/qrtr/qsr.c:277:35: sparse: warning: restricted __le32 degrades to integer
net/qrtr/qsr.c:278:35: sparse: warning: restricted __le32 degrades to integer
net/qrtr/qsr.c:482:16: sparse: warning: symbol 'qsr_handle_ops' was not declared. Should it be static?
# https://github.com/0day-ci/linux/commit/c66a78864319437062e4d506cc771623d0486bae
git remote add linux-review https://github.com/0day-ci/linux
git remote update linux-review
git checkout c66a78864319437062e4d506cc771623d0486bae
vim +116 net/qrtr/qsr.c
c66a78864319437 Wang Wenhu 2020-04-08 102
c66a78864319437 Wang Wenhu 2020-04-08 103 static int qsr_new_server(struct qsr_info *new)
c66a78864319437 Wang Wenhu 2020-04-08 104 {
c66a78864319437 Wang Wenhu 2020-04-08 105 struct qsr_info *lookup;
c66a78864319437 Wang Wenhu 2020-04-08 106 struct qsr_ops *ops = qsr->ops;
c66a78864319437 Wang Wenhu 2020-04-08 107 int ret;
c66a78864319437 Wang Wenhu 2020-04-08 108
c66a78864319437 Wang Wenhu 2020-04-08 109 if (!ops->new_lookup)
c66a78864319437 Wang Wenhu 2020-04-08 110 return 0;
c66a78864319437 Wang Wenhu 2020-04-08 111
c66a78864319437 Wang Wenhu 2020-04-08 112 list_for_each_entry(lookup, &qsr->lookups, list) {
c66a78864319437 Wang Wenhu 2020-04-08 113 if (lookup->service == new->service &&
c66a78864319437 Wang Wenhu 2020-04-08 114 lookup->instance == new->instance) {
c66a78864319437 Wang Wenhu 2020-04-08 115 ret = ops->new_lookup(new,
c66a78864319437 Wang Wenhu 2020-04-08 @116 lookup->client.node,
c66a78864319437 Wang Wenhu 2020-04-08 @117 lookup->client.port);
c66a78864319437 Wang Wenhu 2020-04-08 118 if (ret < 0)
c66a78864319437 Wang Wenhu 2020-04-08 119 pr_err("Error to notice client of new server, %d\n", ret);
c66a78864319437 Wang Wenhu 2020-04-08 120 else
c66a78864319437 Wang Wenhu 2020-04-08 121 list_del(&lookup->list);
c66a78864319437 Wang Wenhu 2020-04-08 122 return 0;
c66a78864319437 Wang Wenhu 2020-04-08 123 }
c66a78864319437 Wang Wenhu 2020-04-08 124 }
c66a78864319437 Wang Wenhu 2020-04-08 125
c66a78864319437 Wang Wenhu 2020-04-08 126 return 0;
c66a78864319437 Wang Wenhu 2020-04-08 127 }
c66a78864319437 Wang Wenhu 2020-04-08 128
c66a78864319437 Wang Wenhu 2020-04-08 129 static int qsr_new_lookup(struct qsr_info *svc, u32 node, u32 port)
c66a78864319437 Wang Wenhu 2020-04-08 130 {
c66a78864319437 Wang Wenhu 2020-04-08 131 struct qrtr_ctrl_pkt pkt;
c66a78864319437 Wang Wenhu 2020-04-08 132 struct sockaddr_qrtr sq;
c66a78864319437 Wang Wenhu 2020-04-08 133 struct msghdr msg = { };
c66a78864319437 Wang Wenhu 2020-04-08 134 struct kvec iv = { &pkt, sizeof(pkt) };
c66a78864319437 Wang Wenhu 2020-04-08 135 int ret = 0;
c66a78864319437 Wang Wenhu 2020-04-08 136
c66a78864319437 Wang Wenhu 2020-04-08 137 memset(&pkt, 0, sizeof(pkt));
c66a78864319437 Wang Wenhu 2020-04-08 138 pkt.cmd = cpu_to_le32(QRTR_TYPE_NEW_SERVER);
c66a78864319437 Wang Wenhu 2020-04-08 139 pkt.server.service = cpu_to_le32(svc->service);
c66a78864319437 Wang Wenhu 2020-04-08 @140 pkt.server.instance = cpu_to_le32(svc->instance);
c66a78864319437 Wang Wenhu 2020-04-08 @141 pkt.server.node = cpu_to_le32(svc->server.node);
c66a78864319437 Wang Wenhu 2020-04-08 142 pkt.server.port = cpu_to_le32(svc->server.port);
c66a78864319437 Wang Wenhu 2020-04-08 143
c66a78864319437 Wang Wenhu 2020-04-08 144 sq.sq_family = AF_QIPCRTR;
c66a78864319437 Wang Wenhu 2020-04-08 145 sq.sq_node = node;
c66a78864319437 Wang Wenhu 2020-04-08 146 sq.sq_port = port;
c66a78864319437 Wang Wenhu 2020-04-08 147
c66a78864319437 Wang Wenhu 2020-04-08 148 msg.msg_name = &sq;
c66a78864319437 Wang Wenhu 2020-04-08 149 msg.msg_namelen = sizeof(sq);
c66a78864319437 Wang Wenhu 2020-04-08 150
c66a78864319437 Wang Wenhu 2020-04-08 151 mutex_lock(&qsr->qsr_lock);
c66a78864319437 Wang Wenhu 2020-04-08 152 if (qsr->sk) {
c66a78864319437 Wang Wenhu 2020-04-08 153 ret = kernel_sendmsg(qsr->sk, &msg, &iv, 1, sizeof(pkt));
c66a78864319437 Wang Wenhu 2020-04-08 154 if (ret < 0)
c66a78864319437 Wang Wenhu 2020-04-08 155 pr_err("Error to send server info to client, %d\n", ret);
c66a78864319437 Wang Wenhu 2020-04-08 156 }
c66a78864319437 Wang Wenhu 2020-04-08 157 mutex_unlock(&qsr->qsr_lock);
c66a78864319437 Wang Wenhu 2020-04-08 158
c66a78864319437 Wang Wenhu 2020-04-08 159 return ret;
c66a78864319437 Wang Wenhu 2020-04-08 160 }
c66a78864319437 Wang Wenhu 2020-04-08 161
c66a78864319437 Wang Wenhu 2020-04-08 162 static void qsr_recv_new_server(u32 service,
c66a78864319437 Wang Wenhu 2020-04-08 163 u32 instance,
c66a78864319437 Wang Wenhu 2020-04-08 164 u32 node,
c66a78864319437 Wang Wenhu 2020-04-08 165 u32 port)
c66a78864319437 Wang Wenhu 2020-04-08 166 {
c66a78864319437 Wang Wenhu 2020-04-08 167 struct qsr_ops *ops = qsr->ops;
c66a78864319437 Wang Wenhu 2020-04-08 168 struct qsr_info *svc, *temp;
c66a78864319437 Wang Wenhu 2020-04-08 169 int ret;
c66a78864319437 Wang Wenhu 2020-04-08 170
c66a78864319437 Wang Wenhu 2020-04-08 171 if (!ops->new_server)
c66a78864319437 Wang Wenhu 2020-04-08 172 return;
c66a78864319437 Wang Wenhu 2020-04-08 173
c66a78864319437 Wang Wenhu 2020-04-08 174 if (!node && !port)
c66a78864319437 Wang Wenhu 2020-04-08 175 return;
c66a78864319437 Wang Wenhu 2020-04-08 176
c66a78864319437 Wang Wenhu 2020-04-08 177 list_for_each_entry(temp, &qsr->services, list) {
c66a78864319437 Wang Wenhu 2020-04-08 @178 if (temp->service == service && temp->instance == instance) {
c66a78864319437 Wang Wenhu 2020-04-08 179 pr_err("Error server exists, service:0x%x instance:0x%x",
c66a78864319437 Wang Wenhu 2020-04-08 180 service, instance);
c66a78864319437 Wang Wenhu 2020-04-08 181 return;
c66a78864319437 Wang Wenhu 2020-04-08 182 }
c66a78864319437 Wang Wenhu 2020-04-08 183 }
c66a78864319437 Wang Wenhu 2020-04-08 184
c66a78864319437 Wang Wenhu 2020-04-08 185 svc = kzalloc(sizeof(*svc), GFP_KERNEL);
c66a78864319437 Wang Wenhu 2020-04-08 186 if (!svc)
c66a78864319437 Wang Wenhu 2020-04-08 187 return;
c66a78864319437 Wang Wenhu 2020-04-08 188
c66a78864319437 Wang Wenhu 2020-04-08 @189 svc->service = service;
c66a78864319437 Wang Wenhu 2020-04-08 @190 svc->instance = instance;
c66a78864319437 Wang Wenhu 2020-04-08 @191 svc->server.node = node;
c66a78864319437 Wang Wenhu 2020-04-08 @192 svc->server.port = port;
c66a78864319437 Wang Wenhu 2020-04-08 193
c66a78864319437 Wang Wenhu 2020-04-08 194 ret = ops->new_server(svc);
c66a78864319437 Wang Wenhu 2020-04-08 195 if (ret < 0)
c66a78864319437 Wang Wenhu 2020-04-08 196 kfree(svc);
c66a78864319437 Wang Wenhu 2020-04-08 197 else
c66a78864319437 Wang Wenhu 2020-04-08 198 list_add(&svc->list, &qsr->services);
c66a78864319437 Wang Wenhu 2020-04-08 199 }
c66a78864319437 Wang Wenhu 2020-04-08 200
---
0-DAY CI Kernel Test Service, Intel Corporation
https://lists.01.org/hyperkitty/list/kbuild-all(a)lists.01.org
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [PATCH RESEND] net: qrtr: support qrtr service and lookup route
2020-04-08 21:33 ` David Miller
@ 2020-04-09 4:18 ` 王文虎
2020-04-09 14:55 ` David Miller
0 siblings, 1 reply; 8+ messages in thread
From: 王文虎 @ 2020-04-09 4:18 UTC (permalink / raw)
To: David Miller
Cc: akpm, kuba, gregkh, tglx, bjorn.andersson, hofrat, allison,
johannes.berg, arnd, cjhuang, linux-kernel, netdev, kernel
From: David Miller <davem@davemloft.net>
Date: 2020-04-09 05:33:27
To: wenhu.wang@vivo.com
Cc: akpm@linux-foundation.org,kuba@kernel.org,gregkh@linuxfoundation.org,tglx@linutronix.de,bjorn.andersson@linaro.org,hofrat@osadl.org,allison@lohutok.net,johannes.berg@intel.com,arnd@arndb.de,cjhuang@codeaurora.org,linux-kernel@vger.kernel.org,netdev@vger.kernel.org,kernel@vivo.com
Subject: Re: [PATCH RESEND] net: qrtr: support qrtr service and lookup route>From: Wang Wenhu <wenhu.wang@vivo.com>
>Date: Wed, 8 Apr 2020 03:46:35 -0700
>
>> QSR implements maintenance of qrtr services and lookups. It would
>> be helpful for developers to work with QRTR without the none-opensource
>> user-space implementation part of IPC Router.
>>
>> As we know, the extremely important point of IPC Router is the support
>> of services form different nodes. But QRTR was pushed into mainline
>> without route process support of services, and the router port process
>> is implemented in user-space as none-opensource codes, which is an
>> great unconvenience for developers.
>>
>> QSR also implements a interface via chardev and a set of sysfs class
>> files for the communication and debugging in user-space. We can get
>> service and lookup entries conveniently via sysfs file in /sys/class/qsr/.
>> Currently add-server, del-server, add-lookup and del-lookup control
>> packatets are processed and enhancements could be taken easily upon
>> currently implementation.
>>
>> Signed-off-by: Wang Wenhu <wenhu.wang@vivo.com>
>
>New features are only appropriate for net-next which is closed right now.
See. And seems like the v5.7-rc1 is probably to be released next monday or so.
I will send a new patch taged with [PATCH net-next] then.
Please deprecate the current commit.
Thanks, Wenhu.
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [PATCH RESEND] net: qrtr: support qrtr service and lookup route
2020-04-08 10:46 [PATCH RESEND] net: qrtr: support qrtr service and lookup route Wang Wenhu
2020-04-08 21:33 ` David Miller
@ 2020-04-09 4:24 ` kbuild test robot
2020-04-09 19:38 ` Bjorn Andersson
2 siblings, 0 replies; 8+ messages in thread
From: kbuild test robot @ 2020-04-09 4:24 UTC (permalink / raw)
To: kbuild-all
[-- Attachment #1: Type: text/plain, Size: 1280 bytes --]
Hi Wang,
Thank you for the patch! Yet something to improve:
[auto build test ERROR on v5.6]
[cannot apply to net-next/master net/master linus/master sparc-next/master next-20200408]
[if your patch is applied to the wrong git tree, please drop us a note to help
improve the system. BTW, we also suggest to use '--base' option to specify the
base tree in git format-patch, please see https://stackoverflow.com/a/37406982]
url: https://github.com/0day-ci/linux/commits/Wang-Wenhu/net-qrtr-support-qrtr-service-and-lookup-route/20200408-234613
base: 7111951b8d4973bda27ff663f2cf18b663d15b48
config: xtensa-allmodconfig (attached as .config)
compiler: xtensa-linux-gcc (GCC) 9.3.0
reproduce:
wget https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross
chmod +x ~/bin/make.cross
# save the attached .config to linux build tree
GCC_VERSION=9.3.0 make.cross ARCH=xtensa
If you fix the issue, kindly add following tag as appropriate
Reported-by: kbuild test robot <lkp@intel.com>
All errors (new ones prefixed by >>):
>> ERROR: "get_qrtr_local_nid" undefined!
---
0-DAY CI Kernel Test Service, Intel Corporation
https://lists.01.org/hyperkitty/list/kbuild-all(a)lists.01.org
[-- Attachment #2: config.gz --]
[-- Type: application/gzip, Size: 61550 bytes --]
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [PATCH RESEND] net: qrtr: support qrtr service and lookup route
2020-04-09 4:18 ` 王文虎
@ 2020-04-09 14:55 ` David Miller
0 siblings, 0 replies; 8+ messages in thread
From: David Miller @ 2020-04-09 14:55 UTC (permalink / raw)
To: wenhu.wang
Cc: akpm, kuba, gregkh, tglx, bjorn.andersson, hofrat, allison,
johannes.berg, arnd, cjhuang, linux-kernel, netdev, kernel
From: 王文虎 <wenhu.wang@vivo.com>
Date: Thu, 9 Apr 2020 12:18:56 +0800 (GMT+08:00)
> See. And seems like the v5.7-rc1 is probably to be released next monday or so.
> I will send a new patch taged with [PATCH net-next] then.
-rc1 being released does not mean that net-next is open.
I explicitly open net-next at the appropriate time and announce it
here on the list, and also the state of net-next is at:
http://vger.kernel.org/~davem/net-next.html
Thank you.
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [PATCH RESEND] net: qrtr: support qrtr service and lookup route
2020-04-08 10:46 [PATCH RESEND] net: qrtr: support qrtr service and lookup route Wang Wenhu
2020-04-08 21:33 ` David Miller
2020-04-09 4:24 ` kbuild test robot
@ 2020-04-09 19:38 ` Bjorn Andersson
2020-04-13 3:55 ` 王文虎
2 siblings, 1 reply; 8+ messages in thread
From: Bjorn Andersson @ 2020-04-09 19:38 UTC (permalink / raw)
To: Wang Wenhu
Cc: akpm, David S. Miller, Jakub Kicinski, Greg Kroah-Hartman,
Thomas Gleixner, Nicholas Mc Guire, Allison Randal, Johannes Berg,
Arnd Bergmann, Carl Huang, linux-kernel, netdev, kernel
On Wed 08 Apr 03:46 PDT 2020, Wang Wenhu wrote:
> QSR implements maintenance of qrtr services and lookups. It would
> be helpful for developers to work with QRTR without the none-opensource
> user-space implementation part of IPC Router.
>
> As we know, the extremely important point of IPC Router is the support
> of services form different nodes. But QRTR was pushed into mainline
> without route process support of services, and the router port process
> is implemented in user-space as none-opensource codes, which is an
> great unconvenience for developers.
>
> QSR also implements a interface via chardev and a set of sysfs class
> files for the communication and debugging in user-space. We can get
> service and lookup entries conveniently via sysfs file in /sys/class/qsr/.
> Currently add-server, del-server, add-lookup and del-lookup control
> packatets are processed and enhancements could be taken easily upon
> currently implementation.
>
> Signed-off-by: Wang Wenhu <wenhu.wang@vivo.com>
Hi Wang,
Isn't this implementing the same thing that was recently landed upstream
as net/qrtr/ns.c?
Regards,
Bjorn
> ---
> Changelog:
> This is a resent, but the first normal version of QSR support.
> The former one sent out earlier contains only the patch of coding
> style modification of qsr.c.
>
> Please do not be confused and take this patch as the NORMAL commit of QSR.
> ---
> net/qrtr/Kconfig | 8 +
> net/qrtr/Makefile | 2 +
> net/qrtr/qrtr.c | 5 +
> net/qrtr/qrtr.h | 2 +
> net/qrtr/qsr.c | 622 ++++++++++++++++++++++++++++++++++++++++++++++
> 5 files changed, 639 insertions(+)
> create mode 100644 net/qrtr/qsr.c
>
> diff --git a/net/qrtr/Kconfig b/net/qrtr/Kconfig
> index 63f89cc6e82c..d2ce8fb57278 100644
> --- a/net/qrtr/Kconfig
> +++ b/net/qrtr/Kconfig
> @@ -29,4 +29,12 @@ config QRTR_TUN
> implement endpoints of QRTR, for purpose of tunneling data to other
> hosts or testing purposes.
>
> +config QSR
> + tristate "QRTR Service Router"
> + help
> + Say Y here to enable the kernel QRTR Service Router module.
> + QSR support route processes of QRTR services and lookups. It would be
> + helpful when develop with QRTR without user-space implementation of
> + IPC Router support.
> +
> endif # QRTR
> diff --git a/net/qrtr/Makefile b/net/qrtr/Makefile
> index 1c6d6c120fb7..3882beaead29 100644
> --- a/net/qrtr/Makefile
> +++ b/net/qrtr/Makefile
> @@ -5,3 +5,5 @@ obj-$(CONFIG_QRTR_SMD) += qrtr-smd.o
> qrtr-smd-y := smd.o
> obj-$(CONFIG_QRTR_TUN) += qrtr-tun.o
> qrtr-tun-y := tun.o
> +obj-$(CONFIG_QSR) += qrtr-svc-router.o
> +qrtr-svc-router-y := qsr.o
> diff --git a/net/qrtr/qrtr.c b/net/qrtr/qrtr.c
> index 5a8e42ad1504..267f7d6c746f 100644
> --- a/net/qrtr/qrtr.c
> +++ b/net/qrtr/qrtr.c
> @@ -158,6 +158,11 @@ static int qrtr_bcast_enqueue(struct qrtr_node *node, struct sk_buff *skb,
> static struct qrtr_sock *qrtr_port_lookup(int port);
> static void qrtr_port_put(struct qrtr_sock *ipc);
>
> +unsigned int get_qrtr_local_nid(void)
> +{
> + return qrtr_local_nid;
> +}
> +
> /* Release node resources and free the node.
> *
> * Do not call directly, use qrtr_node_release. To be used with
> diff --git a/net/qrtr/qrtr.h b/net/qrtr/qrtr.h
> index b81e6953c04b..872d98fd36c6 100644
> --- a/net/qrtr/qrtr.h
> +++ b/net/qrtr/qrtr.h
> @@ -29,4 +29,6 @@ void qrtr_endpoint_unregister(struct qrtr_endpoint *ep);
>
> int qrtr_endpoint_post(struct qrtr_endpoint *ep, const void *data, size_t len);
>
> +unsigned int get_qrtr_local_nid(void);
> +
> #endif
> diff --git a/net/qrtr/qsr.c b/net/qrtr/qsr.c
> new file mode 100644
> index 000000000000..906f5903ebad
> --- /dev/null
> +++ b/net/qrtr/qsr.c
> @@ -0,0 +1,622 @@
> +// SPDX-License-Identifier: GPL-2.0
> +
> +/*
> + * Copyright (C) 2020 Vivo Communication Technology Co. Ltd.
> + * Copyright (C) 2020 Wang Wenhu <wenhu.wang@vivo.com>
> + *
> + * The QRTR Service Route module aims at providing maintenance
> + * and route processes for qrtr service and lookup requests in
> + * kernel. Also, it provides sysfs class interface to expose
> + * the status of qrtr services and lookups. More could be done
> + * through the character device /dev/qsr in user-space.
> + *
> + * Currently, only server add, server delete, lookup add and
> + * lookup delete requests are processed.
> + */
> +
> +#include <linux/module.h>
> +#include <linux/skbuff.h>
> +#include <linux/mutex.h>
> +#include <linux/device.h>
> +#include <linux/string.h>
> +#include <linux/kobject.h>
> +#include <linux/cdev.h>
> +#include <linux/qrtr.h>
> +#include <net/sock.h>
> +
> +#include "qrtr.h"
> +
> +#define QSR_NAME "qsr"
> +
> +/**
> + * struct qsr_info - qrtr service route request information
> + * @service: service identity
> + * @instance: service instance
> + * @server: server address
> + * @client: client address
> + * @node: qrtr node of server or client
> + * @port: qrtr port of server or client
> + *
> + * When a control packet of new server request is received, the server
> + * field should be reference for the server node address. For the opposite
> + * situation, the client field should be referenced within a lookup request.
> + */
> +struct qsr_info {
> + __le32 service;
> + __le32 instance;
> +
> + union {
> + struct {
> + __le32 node;
> + __le32 port;
> + } server;
> +
> + struct {
> + __le32 node;
> + __le32 port;
> + } client;
> + };
> +
> + struct list_head list;
> +};
> +
> +/**
> + * struct qsr - qrtr service route device structure
> + * @dev: character device for user-space communication
> + * @sk: socket to process messages
> + * @sq: socket address to be binded
> + * @ops: callbacks of different control package types
> + * @qsr_lock: data buffer lock
> + * @recv_buf: receive buffer
> + * @recv_buf_size: receive buffer size
> + * @wq: workqueue for message process worker
> + * @work: work route to process queued messages
> + * @lookups: pending lookup requests
> + * @services: servers list to provide different kind of services
> + */
> +struct qsr {
> + struct device dev;
> + struct socket *sk;
> + struct sockaddr_qrtr sq;
> + struct qsr_ops *ops;
> +
> + struct mutex qsr_lock;
> + void *recv_buf;
> + size_t recv_buf_size;
> +
> + struct workqueue_struct *wq;
> + struct work_struct work;
> +
> + struct list_head lookups;
> + struct list_head services;
> +};
> +
> +struct qsr_ops {
> + int (*new_server)(struct qsr_info *svc);
> + int (*new_lookup)(struct qsr_info *svc, u32 node, u32 port);
> +};
> +
> +static int qsr_major;
> +static struct cdev *qsr_cdev;
> +static struct qsr *qsr;
> +
> +static int qsr_new_server(struct qsr_info *new)
> +{
> + struct qsr_info *lookup;
> + struct qsr_ops *ops = qsr->ops;
> + int ret;
> +
> + if (!ops->new_lookup)
> + return 0;
> +
> + list_for_each_entry(lookup, &qsr->lookups, list) {
> + if (lookup->service == new->service &&
> + lookup->instance == new->instance) {
> + ret = ops->new_lookup(new,
> + lookup->client.node,
> + lookup->client.port);
> + if (ret < 0)
> + pr_err("Error to notice client of new server, %d\n", ret);
> + else
> + list_del(&lookup->list);
> + return 0;
> + }
> + }
> +
> + return 0;
> +}
> +
> +static int qsr_new_lookup(struct qsr_info *svc, u32 node, u32 port)
> +{
> + struct qrtr_ctrl_pkt pkt;
> + struct sockaddr_qrtr sq;
> + struct msghdr msg = { };
> + struct kvec iv = { &pkt, sizeof(pkt) };
> + int ret = 0;
> +
> + memset(&pkt, 0, sizeof(pkt));
> + pkt.cmd = cpu_to_le32(QRTR_TYPE_NEW_SERVER);
> + pkt.server.service = cpu_to_le32(svc->service);
> + pkt.server.instance = cpu_to_le32(svc->instance);
> + pkt.server.node = cpu_to_le32(svc->server.node);
> + pkt.server.port = cpu_to_le32(svc->server.port);
> +
> + sq.sq_family = AF_QIPCRTR;
> + sq.sq_node = node;
> + sq.sq_port = port;
> +
> + msg.msg_name = &sq;
> + msg.msg_namelen = sizeof(sq);
> +
> + mutex_lock(&qsr->qsr_lock);
> + if (qsr->sk) {
> + ret = kernel_sendmsg(qsr->sk, &msg, &iv, 1, sizeof(pkt));
> + if (ret < 0)
> + pr_err("Error to send server info to client, %d\n", ret);
> + }
> + mutex_unlock(&qsr->qsr_lock);
> +
> + return ret;
> +}
> +
> +static void qsr_recv_new_server(u32 service,
> + u32 instance,
> + u32 node,
> + u32 port)
> +{
> + struct qsr_ops *ops = qsr->ops;
> + struct qsr_info *svc, *temp;
> + int ret;
> +
> + if (!ops->new_server)
> + return;
> +
> + if (!node && !port)
> + return;
> +
> + list_for_each_entry(temp, &qsr->services, list) {
> + if (temp->service == service && temp->instance == instance) {
> + pr_err("Error server exists, service:0x%x instance:0x%x",
> + service, instance);
> + return;
> + }
> + }
> +
> + svc = kzalloc(sizeof(*svc), GFP_KERNEL);
> + if (!svc)
> + return;
> +
> + svc->service = service;
> + svc->instance = instance;
> + svc->server.node = node;
> + svc->server.port = port;
> +
> + ret = ops->new_server(svc);
> + if (ret < 0)
> + kfree(svc);
> + else
> + list_add(&svc->list, &qsr->services);
> +}
> +
> +static void qsr_recv_del_server(u32 service, u32 instance)
> +{
> + struct qsr_info *svc;
> +
> + list_for_each_entry(svc, &qsr->lookups, list) {
> + if (svc->service == service && svc->instance == instance) {
> + list_del(&svc->list);
> + return;
> + }
> + }
> +}
> +
> +static void qsr_recv_new_lookup(u32 service,
> + u32 instance,
> + u32 node,
> + u32 port)
> +{
> + struct qsr_ops *ops = qsr->ops;
> + struct qsr_info *svc, *temp;
> + int ret;
> +
> + if (!ops->new_lookup)
> + return;
> +
> + if (!node && !port)
> + return;
> +
> + list_for_each_entry(temp, &qsr->lookups, list) {
> + if (temp->service == service &&
> + temp->instance == instance &&
> + temp->client.node == node &&
> + temp->client.port == port) {
> + pr_err("Error lookup exists, service:0x%x instance:0x%x node:%d port:%d",
> + service, instance, node, port);
> + return;
> + }
> + }
> +
> + list_for_each_entry(svc, &qsr->services, list) {
> + if (svc->service == service && svc->instance == instance) {
> + ret = ops->new_lookup(svc, node, port);
> + if (ret < 0)
> + pr_err("Error to send server info to client, %d", ret);
> + return;
> + }
> + }
> +
> + /* Server does not exist.
> + * Record the lookup information and add it to the pending list.
> + */
> +
> + svc = kzalloc(sizeof(*svc), GFP_KERNEL);
> + if (!svc)
> + return;
> +
> + svc->service = service;
> + svc->instance = instance;
> + svc->client.node = node;
> + svc->client.port = port;
> +
> + list_add(&svc->list, &qsr->lookups);
> +}
> +
> +static void qsr_recv_del_lookup(u32 service,
> + u32 instance,
> + u32 node,
> + u32 port)
> +{
> + struct qsr_info *lookup;
> +
> + if (!node && !port)
> + return;
> +
> + list_for_each_entry(lookup, &qsr->lookups, list) {
> + if (lookup->service == service &&
> + lookup->instance == instance &&
> + lookup->client.node == node &&
> + lookup->client.port == port) {
> + list_del(&lookup->list);
> + return;
> + }
> + }
> +}
> +
> +static void qsr_recv_ctrl_pkt(struct sockaddr_qrtr *sq,
> + const void *buf,
> + size_t len)
> +{
> + const struct qrtr_ctrl_pkt *pkt = buf;
> +
> + if (len < sizeof(struct qrtr_ctrl_pkt)) {
> + pr_debug("ignoring short control packet\n");
> + return;
> + }
> +
> + switch (le32_to_cpu(pkt->cmd)) {
> + case QRTR_TYPE_NEW_SERVER:
> + qsr_recv_new_server(le32_to_cpu(pkt->server.service),
> + le32_to_cpu(pkt->server.instance),
> + le32_to_cpu(pkt->server.node),
> + le32_to_cpu(pkt->server.port));
> + break;
> +
> + case QRTR_TYPE_NEW_LOOKUP:
> + qsr_recv_new_lookup(le32_to_cpu(pkt->server.service),
> + le32_to_cpu(pkt->server.instance),
> + sq->sq_node,
> + sq->sq_port);
> + break;
> +
> + case QRTR_TYPE_DEL_SERVER:
> + qsr_recv_del_server(le32_to_cpu(pkt->server.service),
> + le32_to_cpu(pkt->server.instance));
> + break;
> +
> + case QRTR_TYPE_DEL_LOOKUP:
> + qsr_recv_del_lookup(le32_to_cpu(pkt->server.service),
> + le32_to_cpu(pkt->server.instance),
> + sq->sq_node,
> + sq->sq_port);
> + break;
> + }
> +}
> +
> +static void qsr_recv_work(struct work_struct *work)
> +{
> + struct sockaddr_qrtr sq;
> + struct msghdr msg = { .msg_name = &sq, .msg_namelen = sizeof(sq) };
> + struct kvec iv;
> + ssize_t msglen;
> +
> + for (;;) {
> + iv.iov_base = qsr->recv_buf;
> + iv.iov_len = qsr->recv_buf_size;
> +
> + mutex_lock(&qsr->qsr_lock);
> + if (qsr->sk)
> + msglen = kernel_recvmsg(qsr->sk, &msg, &iv, 1,
> + iv.iov_len, MSG_DONTWAIT);
> + else
> + msglen = -EPIPE;
> + mutex_unlock(&qsr->qsr_lock);
> +
> + if (msglen == -EAGAIN)
> + break;
> +
> + if (msglen < 0) {
> + pr_err("qmi recvmsg failed: %zd\n", msglen);
> + break;
> + }
> +
> + qsr_recv_ctrl_pkt(&sq, qsr->recv_buf, msglen);
> + }
> +}
> +
> +static void qsr_data_ready(struct sock *sk)
> +{
> + read_lock_bh(&sk->sk_callback_lock);
> + queue_work(qsr->wq, &qsr->work);
> + read_unlock_bh(&sk->sk_callback_lock);
> +}
> +
> +static ssize_t name_show(struct device *dev,
> + struct device_attribute *attr, char *buf)
> +{
> + int ret;
> +
> + mutex_lock(&qsr->qsr_lock);
> + ret = sprintf(buf, "%s\n", QSR_NAME);
> + mutex_unlock(&qsr->qsr_lock);
> +
> + return ret;
> +}
> +static DEVICE_ATTR_RO(name);
> +
> +static ssize_t lookups_show(struct device *dev,
> + struct device_attribute *attr, char *buf)
> +{
> + struct qsr_info *lookup;
> + int ret = 0;
> +
> + mutex_lock(&qsr->qsr_lock);
> + list_for_each_entry(lookup, &qsr->lookups, list) {
> + ret += sprintf(buf, "service:0x%04x instance:0x%04x node:%04d port:%04d\n",
> + lookup->service,
> + lookup->instance,
> + lookup->server.node,
> + lookup->server.port);
> + }
> + mutex_unlock(&qsr->qsr_lock);
> +
> + return ret;
> +}
> +static DEVICE_ATTR_RO(lookups);
> +
> +static ssize_t services_show(struct device *dev,
> + struct device_attribute *attr,
> + char *buf)
> +{
> + struct qsr_info *svc;
> + int ret = 0;
> +
> + mutex_lock(&qsr->qsr_lock);
> + list_for_each_entry(svc, &qsr->services, list) {
> + ret += sprintf(buf, "service:0x%04x instance:0x%04x node:%04d port:%04d\n",
> + svc->service,
> + svc->instance,
> + svc->server.node,
> + svc->server.port);
> + }
> + mutex_unlock(&qsr->qsr_lock);
> +
> + return ret;
> +}
> +static DEVICE_ATTR_RO(services);
> +
> +static struct attribute *qsr_attrs[] = {
> + &dev_attr_name.attr,
> + &dev_attr_lookups.attr,
> + &dev_attr_services.attr,
> + NULL,
> +};
> +ATTRIBUTE_GROUPS(qsr);
> +
> +/* Interface class infrastructure. */
> +static struct class qsr_class = {
> + .name = QSR_NAME,
> + .dev_groups = qsr_groups,
> +};
> +
> +static int qsr_dev_create(void)
> +{
> + int ret = -ENOMEM;
> +
> + qsr = kzalloc(sizeof(*qsr), GFP_KERNEL);
> + if (!qsr)
> + goto out;
> +
> + INIT_LIST_HEAD(&qsr->lookups);
> + INIT_LIST_HEAD(&qsr->services);
> +
> + INIT_WORK(&qsr->work, qsr_recv_work);
> +
> + qsr->recv_buf_size = sizeof(struct qrtr_ctrl_pkt);
> + qsr->recv_buf = kzalloc(qsr->recv_buf_size, GFP_KERNEL);
> + if (!qsr->recv_buf)
> + goto out_qsr_free;
> +
> + qsr->wq = alloc_workqueue("qsr_wq", WQ_UNBOUND, 1);
> + if (!qsr->wq)
> + goto out_recv_buf_free;
> +
> + device_initialize(&qsr->dev);
> + qsr->dev.devt = MKDEV(qsr_major, 0);
> + qsr->dev.class = &qsr_class;
> + dev_set_drvdata(&qsr->dev, qsr);
> +
> + ret = dev_set_name(&qsr->dev, QSR_NAME);
> + if (ret) {
> + pr_err("device name %s set failed, %d", QSR_NAME, ret);
> + goto out_recv_buf_free;
> + }
> +
> + mutex_init(&qsr->qsr_lock);
> +
> + ret = device_add(&qsr->dev);
> + if (ret)
> + goto out_wq_destroy;
> +
> + return ret;
> +
> +out_wq_destroy:
> + destroy_workqueue(qsr->wq);
> +out_recv_buf_free:
> + kfree(qsr->recv_buf);
> +out_qsr_free:
> + kfree(qsr);
> +out:
> + return ret;
> +}
> +
> +struct qsr_ops qsr_handle_ops = {
> + .new_server = qsr_new_server,
> + .new_lookup = qsr_new_lookup,
> +};
> +
> +static struct socket *qsr_sock_create(void)
> +{
> + struct socket *sock;
> + struct sockaddr addr;
> + int ret;
> +
> + ret = sock_create_kern(&init_net, AF_QIPCRTR, SOCK_DGRAM,
> + PF_QIPCRTR, &sock);
> +
> + if (ret < 0)
> + return ERR_PTR(ret);
> +
> + qsr->sq.sq_family = AF_QIPCRTR;
> + qsr->sq.sq_node = get_qrtr_local_nid();
> + qsr->sq.sq_port = QRTR_PORT_CTRL;
> + qsr->ops = &qsr_handle_ops;
> +
> + if (sock->ops->bind) {
> + memcpy(&addr, &qsr->sq, sizeof(qsr->sq));
> + ret = sock->ops->bind(sock, &addr, sizeof(addr));
> + if (ret) {
> + pr_err("Failed to bind socket address node:0x%x port:0x%x.\n",
> + qsr->sq.sq_node, qsr->sq.sq_port);
> + goto err_bind;
> + }
> + pr_debug("qsr router port binded successfully.\n");
> + }
> +
> + sock->sk->sk_user_data = qsr;
> + sock->sk->sk_data_ready = qsr_data_ready;
> + sock->sk->sk_error_report = qsr_data_ready;
> + sock->sk->sk_sndtimeo = HZ * 10;
> +
> + return sock;
> +
> +err_bind:
> + sock_release(sock);
> + return NULL;
> +}
> +
> +static int qsr_release(void)
> +{
> + sock_release(qsr->sk);
> +
> + kfree(qsr->recv_buf);
> +
> + destroy_workqueue(qsr->wq);
> +
> + kfree(qsr);
> +
> + return 0;
> +}
> +
> +static const struct file_operations qsr_fops = {
> + .owner = THIS_MODULE,
> +};
> +
> +static int __init qsr_init(void)
> +{
> + int ret;
> + static const char name[] = QSR_NAME;
> + struct cdev *cdev = NULL;
> + dev_t rtdev;
> +
> + /* 1. Allocate character device region. */
> + ret = alloc_chrdev_region(&rtdev, 0, 1, name);
> + if (ret) {
> + pr_err("failed to alloc chardev region\n");
> + goto out;
> + }
> +
> + /* 2. Allocate, initiate and add cdev. */
> + ret = -ENOMEM;
> + cdev = cdev_alloc();
> + if (!cdev) {
> + pr_err("failed to alloc cdev\n");
> + goto out_unregister;
> + }
> +
> + cdev->owner = THIS_MODULE;
> + cdev->ops = &qsr_fops;
> + kobject_set_name(&cdev->kobj, "%s", name);
> +
> + ret = cdev_add(cdev, rtdev, 1);
> + if (ret)
> + goto out_put;
> +
> + qsr_major = MAJOR(rtdev);
> + qsr_cdev = cdev;
> +
> + /* 3. Register class. */
> + ret = class_register(&qsr_class);
> + if (ret) {
> + pr_err("class_register failed for qrtr route\n");
> + goto out_cdev_del;
> + }
> +
> + /* 4. Create a qsr device. */
> + if (qsr_dev_create())
> + goto out_unregister_class;
> +
> + /* 5. Create a qrtr socket and bind it to Router port. */
> + qsr->sk = qsr_sock_create();
> + if (!qsr->sk)
> + goto out_qsr_dev_del;
> +
> + return 0;
> +
> +out_qsr_dev_del:
> + kfree(qsr);
> +out_unregister_class:
> + class_unregister(&qsr_class);
> +out_cdev_del:
> + cdev_del(qsr_cdev);
> +out_put:
> + kobject_put(&cdev->kobj);
> +out_unregister:
> + unregister_chrdev_region(rtdev, 1);
> +out:
> + return ret;
> +}
> +subsys_initcall(qsr_init);
> +
> +static void __exit qsr_exit(void)
> +{
> + qsr_release();
> + unregister_chrdev_region(MKDEV(qsr_major, 0), 1);
> + cdev_del(qsr_cdev);
> + class_unregister(&qsr_class);
> +}
> +module_exit(qsr_exit);
> +
> +MODULE_AUTHOR("Wang Wenhu");
> +MODULE_ALIAS("QRTR:" QSR_NAME);
> +MODULE_DESCRIPTION("Qualcomm IPC Router Service Route Support");
> +MODULE_LICENSE("GPL v2");
> --
> 2.17.1
>
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [PATCH RESEND] net: qrtr: support qrtr service and lookup route
2020-04-09 19:38 ` Bjorn Andersson
@ 2020-04-13 3:55 ` 王文虎
0 siblings, 0 replies; 8+ messages in thread
From: 王文虎 @ 2020-04-13 3:55 UTC (permalink / raw)
To: Bjorn Andersson
Cc: akpm, David S. Miller, Jakub Kicinski, Greg Kroah-Hartman,
Thomas Gleixner, Nicholas Mc Guire, Allison Randal, Johannes Berg,
Arnd Bergmann, Carl Huang, linux-kernel, netdev, kernel
From: Bjorn Andersson <bjorn.andersson@linaro.org>
Date: 2020-04-10 03:38:07
To: Wang Wenhu <wenhu.wang@vivo.com>
Cc: akpm@linux-foundation.org,"David S. Miller" <davem@davemloft.net>,Jakub Kicinski <kuba@kernel.org>,Greg Kroah-Hartman <gregkh@linuxfoundation.org>,Thomas Gleixner <tglx@linutronix.de>,Nicholas Mc Guire <hofrat@osadl.org>,Allison Randal <allison@lohutok.net>,Johannes Berg <johannes.berg@intel.com>,Arnd Bergmann <arnd@arndb.de>,Carl Huang <cjhuang@codeaurora.org>,linux-kernel@vger.kernel.org,netdev@vger.kernel.org,kernel@vivo.com
Subject: Re: [PATCH RESEND] net: qrtr: support qrtr service and lookup route>On Wed 08 Apr 03:46 PDT 2020, Wang Wenhu wrote:
>
>> QSR implements maintenance of qrtr services and lookups. It would
>> be helpful for developers to work with QRTR without the none-opensource
>> user-space implementation part of IPC Router.
>>
>> As we know, the extremely important point of IPC Router is the support
>> of services form different nodes. But QRTR was pushed into mainline
>> without route process support of services, and the router port process
>> is implemented in user-space as none-opensource codes, which is an
>> great unconvenience for developers.
>>
>> QSR also implements a interface via chardev and a set of sysfs class
>> files for the communication and debugging in user-space. We can get
>> service and lookup entries conveniently via sysfs file in /sys/class/qsr/.
>> Currently add-server, del-server, add-lookup and del-lookup control
>> packatets are processed and enhancements could be taken easily upon
>> currently implementation.
>>
>> Signed-off-by: Wang Wenhu <wenhu.wang@vivo.com>
>
>Hi Wang,
>
>Isn't this implementing the same thing that was recently landed upstream
>as net/qrtr/ns.c?
>
Hi, Regards
I found the qmi-service-maintainence had been missing since QRTR was introduced
recently while I was busy working with another new driver which I would name
it RPMON(Remote Processor Monitor). I konw the maintainence is supported
in user level but did not find any opensource code.
As you mentioned ns,c, let me check it out first.
As for RPMON, I have sent it out to Greg KH.
https://lore.kernel.org/lkml/20200412112405.24116-1-wenhu.wang@vivo.com/
Thanks,
Wenhu
>Regards,
>Bjorn
>
>> ---
>> Changelog:
>> This is a resent, but the first normal version of QSR support.
>> The former one sent out earlier contains only the patch of coding
>> style modification of qsr.c.
>>
>> Please do not be confused and take this patch as the NORMAL commit of QSR.
>> ---
>> net/qrtr/Kconfig | 8 +
>> net/qrtr/Makefile | 2 +
>> net/qrtr/qrtr.c | 5 +
>> net/qrtr/qrtr.h | 2 +
>> net/qrtr/qsr.c | 622 ++++++++++++++++++++++++++++++++++++++++++++++
>> 5 files changed, 639 insertions(+)
>> create mode 100644 net/qrtr/qsr.c
>>
>> diff --git a/net/qrtr/Kconfig b/net/qrtr/Kconfig
>> index 63f89cc6e82c..d2ce8fb57278 100644
>> --- a/net/qrtr/Kconfig
>> +++ b/net/qrtr/Kconfig
>> @@ -29,4 +29,12 @@ config QRTR_TUN
>> implement endpoints of QRTR, for purpose of tunneling data to other
>> hosts or testing purposes.
>>
>> +config QSR
>> + tristate "QRTR Service Router"
>> + help
>> + Say Y here to enable the kernel QRTR Service Router module.
>> + QSR support route processes of QRTR services and lookups. It would be
>> + helpful when develop with QRTR without user-space implementation of
>> + IPC Router support.
>> +
>> endif # QRTR
>> diff --git a/net/qrtr/Makefile b/net/qrtr/Makefile
>> index 1c6d6c120fb7..3882beaead29 100644
>> --- a/net/qrtr/Makefile
>> +++ b/net/qrtr/Makefile
>> @@ -5,3 +5,5 @@ obj-$(CONFIG_QRTR_SMD) += qrtr-smd.o
>> qrtr-smd-y := smd.o
>> obj-$(CONFIG_QRTR_TUN) += qrtr-tun.o
>> qrtr-tun-y := tun.o
>> +obj-$(CONFIG_QSR) += qrtr-svc-router.o
>> +qrtr-svc-router-y := qsr.o
>> diff --git a/net/qrtr/qrtr.c b/net/qrtr/qrtr.c
>> index 5a8e42ad1504..267f7d6c746f 100644
>> --- a/net/qrtr/qrtr.c
>> +++ b/net/qrtr/qrtr.c
>> @@ -158,6 +158,11 @@ static int qrtr_bcast_enqueue(struct qrtr_node *node, struct sk_buff *skb,
>> static struct qrtr_sock *qrtr_port_lookup(int port);
>> static void qrtr_port_put(struct qrtr_sock *ipc);
>>
>> +unsigned int get_qrtr_local_nid(void)
>> +{
>> + return qrtr_local_nid;
>> +}
>> +
>> /* Release node resources and free the node.
>> *
>> * Do not call directly, use qrtr_node_release. To be used with
>> diff --git a/net/qrtr/qrtr.h b/net/qrtr/qrtr.h
>> index b81e6953c04b..872d98fd36c6 100644
>> --- a/net/qrtr/qrtr.h
>> +++ b/net/qrtr/qrtr.h
>> @@ -29,4 +29,6 @@ void qrtr_endpoint_unregister(struct qrtr_endpoint *ep);
>>
>> int qrtr_endpoint_post(struct qrtr_endpoint *ep, const void *data, size_t len);
>>
>> +unsigned int get_qrtr_local_nid(void);
>> +
>> #endif
>> diff --git a/net/qrtr/qsr.c b/net/qrtr/qsr.c
>> new file mode 100644
>> index 000000000000..906f5903ebad
>> --- /dev/null
>> +++ b/net/qrtr/qsr.c
>> @@ -0,0 +1,622 @@
>> +// SPDX-License-Identifier: GPL-2.0
>> +
>> +/*
>> + * Copyright (C) 2020 Vivo Communication Technology Co. Ltd.
>> + * Copyright (C) 2020 Wang Wenhu <wenhu.wang@vivo.com>
>> + *
>> + * The QRTR Service Route module aims at providing maintenance
>> + * and route processes for qrtr service and lookup requests in
>> + * kernel. Also, it provides sysfs class interface to expose
>> + * the status of qrtr services and lookups. More could be done
>> + * through the character device /dev/qsr in user-space.
>> + *
>> + * Currently, only server add, server delete, lookup add and
>> + * lookup delete requests are processed.
>> + */
>> +
>> +#include <linux/module.h>
>> +#include <linux/skbuff.h>
>> +#include <linux/mutex.h>
>> +#include <linux/device.h>
>> +#include <linux/string.h>
>> +#include <linux/kobject.h>
>> +#include <linux/cdev.h>
>> +#include <linux/qrtr.h>
>> +#include <net/sock.h>
>> +
>> +#include "qrtr.h"
>> +
>> +#define QSR_NAME "qsr"
>> +
>> +/**
>> + * struct qsr_info - qrtr service route request information
>> + * @service: service identity
>> + * @instance: service instance
>> + * @server: server address
>> + * @client: client address
>> + * @node: qrtr node of server or client
>> + * @port: qrtr port of server or client
>> + *
>> + * When a control packet of new server request is received, the server
>> + * field should be reference for the server node address. For the opposite
>> + * situation, the client field should be referenced within a lookup request.
>> + */
>> +struct qsr_info {
>> + __le32 service;
>> + __le32 instance;
>> +
>> + union {
>> + struct {
>> + __le32 node;
>> + __le32 port;
>> + } server;
>> +
>> + struct {
>> + __le32 node;
>> + __le32 port;
>> + } client;
>> + };
>> +
>> + struct list_head list;
>> +};
>> +
>> +/**
>> + * struct qsr - qrtr service route device structure
>> + * @dev: character device for user-space communication
>> + * @sk: socket to process messages
>> + * @sq: socket address to be binded
>> + * @ops: callbacks of different control package types
>> + * @qsr_lock: data buffer lock
>> + * @recv_buf: receive buffer
>> + * @recv_buf_size: receive buffer size
>> + * @wq: workqueue for message process worker
>> + * @work: work route to process queued messages
>> + * @lookups: pending lookup requests
>> + * @services: servers list to provide different kind of services
>> + */
>> +struct qsr {
>> + struct device dev;
>> + struct socket *sk;
>> + struct sockaddr_qrtr sq;
>> + struct qsr_ops *ops;
>> +
>> + struct mutex qsr_lock;
>> + void *recv_buf;
>> + size_t recv_buf_size;
>> +
>> + struct workqueue_struct *wq;
>> + struct work_struct work;
>> +
>> + struct list_head lookups;
>> + struct list_head services;
>> +};
>> +
>> +struct qsr_ops {
>> + int (*new_server)(struct qsr_info *svc);
>> + int (*new_lookup)(struct qsr_info *svc, u32 node, u32 port);
>> +};
>> +
>> +static int qsr_major;
>> +static struct cdev *qsr_cdev;
>> +static struct qsr *qsr;
>> +
>> +static int qsr_new_server(struct qsr_info *new)
>> +{
>> + struct qsr_info *lookup;
>> + struct qsr_ops *ops = qsr->ops;
>> + int ret;
>> +
>> + if (!ops->new_lookup)
>> + return 0;
>> +
>> + list_for_each_entry(lookup, &qsr->lookups, list) {
>> + if (lookup->service == new->service &&
>> + lookup->instance == new->instance) {
>> + ret = ops->new_lookup(new,
>> + lookup->client.node,
>> + lookup->client.port);
>> + if (ret < 0)
>> + pr_err("Error to notice client of new server, %d\n", ret);
>> + else
>> + list_del(&lookup->list);
>> + return 0;
>> + }
>> + }
>> +
>> + return 0;
>> +}
>> +
>> +static int qsr_new_lookup(struct qsr_info *svc, u32 node, u32 port)
>> +{
>> + struct qrtr_ctrl_pkt pkt;
>> + struct sockaddr_qrtr sq;
>> + struct msghdr msg = { };
>> + struct kvec iv = { &pkt, sizeof(pkt) };
>> + int ret = 0;
>> +
>> + memset(&pkt, 0, sizeof(pkt));
>> + pkt.cmd = cpu_to_le32(QRTR_TYPE_NEW_SERVER);
>> + pkt.server.service = cpu_to_le32(svc->service);
>> + pkt.server.instance = cpu_to_le32(svc->instance);
>> + pkt.server.node = cpu_to_le32(svc->server.node);
>> + pkt.server.port = cpu_to_le32(svc->server.port);
>> +
>> + sq.sq_family = AF_QIPCRTR;
>> + sq.sq_node = node;
>> + sq.sq_port = port;
>> +
>> + msg.msg_name = &sq;
>> + msg.msg_namelen = sizeof(sq);
>> +
>> + mutex_lock(&qsr->qsr_lock);
>> + if (qsr->sk) {
>> + ret = kernel_sendmsg(qsr->sk, &msg, &iv, 1, sizeof(pkt));
>> + if (ret < 0)
>> + pr_err("Error to send server info to client, %d\n", ret);
>> + }
>> + mutex_unlock(&qsr->qsr_lock);
>> +
>> + return ret;
>> +}
>> +
>> +static void qsr_recv_new_server(u32 service,
>> + u32 instance,
>> + u32 node,
>> + u32 port)
>> +{
>> + struct qsr_ops *ops = qsr->ops;
>> + struct qsr_info *svc, *temp;
>> + int ret;
>> +
>> + if (!ops->new_server)
>> + return;
>> +
>> + if (!node && !port)
>> + return;
>> +
>> + list_for_each_entry(temp, &qsr->services, list) {
>> + if (temp->service == service && temp->instance == instance) {
>> + pr_err("Error server exists, service:0x%x instance:0x%x",
>> + service, instance);
>> + return;
>> + }
>> + }
>> +
>> + svc = kzalloc(sizeof(*svc), GFP_KERNEL);
>> + if (!svc)
>> + return;
>> +
>> + svc->service = service;
>> + svc->instance = instance;
>> + svc->server.node = node;
>> + svc->server.port = port;
>> +
>> + ret = ops->new_server(svc);
>> + if (ret < 0)
>> + kfree(svc);
>> + else
>> + list_add(&svc->list, &qsr->services);
>> +}
>> +
>> +static void qsr_recv_del_server(u32 service, u32 instance)
>> +{
>> + struct qsr_info *svc;
>> +
>> + list_for_each_entry(svc, &qsr->lookups, list) {
>> + if (svc->service == service && svc->instance == instance) {
>> + list_del(&svc->list);
>> + return;
>> + }
>> + }
>> +}
>> +
>> +static void qsr_recv_new_lookup(u32 service,
>> + u32 instance,
>> + u32 node,
>> + u32 port)
>> +{
>> + struct qsr_ops *ops = qsr->ops;
>> + struct qsr_info *svc, *temp;
>> + int ret;
>> +
>> + if (!ops->new_lookup)
>> + return;
>> +
>> + if (!node && !port)
>> + return;
>> +
>> + list_for_each_entry(temp, &qsr->lookups, list) {
>> + if (temp->service == service &&
>> + temp->instance == instance &&
>> + temp->client.node == node &&
>> + temp->client.port == port) {
>> + pr_err("Error lookup exists, service:0x%x instance:0x%x node:%d port:%d",
>> + service, instance, node, port);
>> + return;
>> + }
>> + }
>> +
>> + list_for_each_entry(svc, &qsr->services, list) {
>> + if (svc->service == service && svc->instance == instance) {
>> + ret = ops->new_lookup(svc, node, port);
>> + if (ret < 0)
>> + pr_err("Error to send server info to client, %d", ret);
>> + return;
>> + }
>> + }
>> +
>> + /* Server does not exist.
>> + * Record the lookup information and add it to the pending list.
>> + */
>> +
>> + svc = kzalloc(sizeof(*svc), GFP_KERNEL);
>> + if (!svc)
>> + return;
>> +
>> + svc->service = service;
>> + svc->instance = instance;
>> + svc->client.node = node;
>> + svc->client.port = port;
>> +
>> + list_add(&svc->list, &qsr->lookups);
>> +}
>> +
>> +static void qsr_recv_del_lookup(u32 service,
>> + u32 instance,
>> + u32 node,
>> + u32 port)
>> +{
>> + struct qsr_info *lookup;
>> +
>> + if (!node && !port)
>> + return;
>> +
>> + list_for_each_entry(lookup, &qsr->lookups, list) {
>> + if (lookup->service == service &&
>> + lookup->instance == instance &&
>> + lookup->client.node == node &&
>> + lookup->client.port == port) {
>> + list_del(&lookup->list);
>> + return;
>> + }
>> + }
>> +}
>> +
>> +static void qsr_recv_ctrl_pkt(struct sockaddr_qrtr *sq,
>> + const void *buf,
>> + size_t len)
>> +{
>> + const struct qrtr_ctrl_pkt *pkt = buf;
>> +
>> + if (len < sizeof(struct qrtr_ctrl_pkt)) {
>> + pr_debug("ignoring short control packet\n");
>> + return;
>> + }
>> +
>> + switch (le32_to_cpu(pkt->cmd)) {
>> + case QRTR_TYPE_NEW_SERVER:
>> + qsr_recv_new_server(le32_to_cpu(pkt->server.service),
>> + le32_to_cpu(pkt->server.instance),
>> + le32_to_cpu(pkt->server.node),
>> + le32_to_cpu(pkt->server.port));
>> + break;
>> +
>> + case QRTR_TYPE_NEW_LOOKUP:
>> + qsr_recv_new_lookup(le32_to_cpu(pkt->server.service),
>> + le32_to_cpu(pkt->server.instance),
>> + sq->sq_node,
>> + sq->sq_port);
>> + break;
>> +
>> + case QRTR_TYPE_DEL_SERVER:
>> + qsr_recv_del_server(le32_to_cpu(pkt->server.service),
>> + le32_to_cpu(pkt->server.instance));
>> + break;
>> +
>> + case QRTR_TYPE_DEL_LOOKUP:
>> + qsr_recv_del_lookup(le32_to_cpu(pkt->server.service),
>> + le32_to_cpu(pkt->server.instance),
>> + sq->sq_node,
>> + sq->sq_port);
>> + break;
>> + }
>> +}
>> +
>> +static void qsr_recv_work(struct work_struct *work)
>> +{
>> + struct sockaddr_qrtr sq;
>> + struct msghdr msg = { .msg_name = &sq, .msg_namelen = sizeof(sq) };
>> + struct kvec iv;
>> + ssize_t msglen;
>> +
>> + for (;;) {
>> + iv.iov_base = qsr->recv_buf;
>> + iv.iov_len = qsr->recv_buf_size;
>> +
>> + mutex_lock(&qsr->qsr_lock);
>> + if (qsr->sk)
>> + msglen = kernel_recvmsg(qsr->sk, &msg, &iv, 1,
>> + iv.iov_len, MSG_DONTWAIT);
>> + else
>> + msglen = -EPIPE;
>> + mutex_unlock(&qsr->qsr_lock);
>> +
>> + if (msglen == -EAGAIN)
>> + break;
>> +
>> + if (msglen < 0) {
>> + pr_err("qmi recvmsg failed: %zd\n", msglen);
>> + break;
>> + }
>> +
>> + qsr_recv_ctrl_pkt(&sq, qsr->recv_buf, msglen);
>> + }
>> +}
>> +
>> +static void qsr_data_ready(struct sock *sk)
>> +{
>> + read_lock_bh(&sk->sk_callback_lock);
>> + queue_work(qsr->wq, &qsr->work);
>> + read_unlock_bh(&sk->sk_callback_lock);
>> +}
>> +
>> +static ssize_t name_show(struct device *dev,
>> + struct device_attribute *attr, char *buf)
>> +{
>> + int ret;
>> +
>> + mutex_lock(&qsr->qsr_lock);
>> + ret = sprintf(buf, "%s\n", QSR_NAME);
>> + mutex_unlock(&qsr->qsr_lock);
>> +
>> + return ret;
>> +}
>> +static DEVICE_ATTR_RO(name);
>> +
>> +static ssize_t lookups_show(struct device *dev,
>> + struct device_attribute *attr, char *buf)
>> +{
>> + struct qsr_info *lookup;
>> + int ret = 0;
>> +
>> + mutex_lock(&qsr->qsr_lock);
>> + list_for_each_entry(lookup, &qsr->lookups, list) {
>> + ret += sprintf(buf, "service:0x%04x instance:0x%04x node:%04d port:%04d\n",
>> + lookup->service,
>> + lookup->instance,
>> + lookup->server.node,
>> + lookup->server.port);
>> + }
>> + mutex_unlock(&qsr->qsr_lock);
>> +
>> + return ret;
>> +}
>> +static DEVICE_ATTR_RO(lookups);
>> +
>> +static ssize_t services_show(struct device *dev,
>> + struct device_attribute *attr,
>> + char *buf)
>> +{
>> + struct qsr_info *svc;
>> + int ret = 0;
>> +
>> + mutex_lock(&qsr->qsr_lock);
>> + list_for_each_entry(svc, &qsr->services, list) {
>> + ret += sprintf(buf, "service:0x%04x instance:0x%04x node:%04d port:%04d\n",
>> + svc->service,
>> + svc->instance,
>> + svc->server.node,
>> + svc->server.port);
>> + }
>> + mutex_unlock(&qsr->qsr_lock);
>> +
>> + return ret;
>> +}
>> +static DEVICE_ATTR_RO(services);
>> +
>> +static struct attribute *qsr_attrs[] = {
>> + &dev_attr_name.attr,
>> + &dev_attr_lookups.attr,
>> + &dev_attr_services.attr,
>> + NULL,
>> +};
>> +ATTRIBUTE_GROUPS(qsr);
>> +
>> +/* Interface class infrastructure. */
>> +static struct class qsr_class = {
>> + .name = QSR_NAME,
>> + .dev_groups = qsr_groups,
>> +};
>> +
>> +static int qsr_dev_create(void)
>> +{
>> + int ret = -ENOMEM;
>> +
>> + qsr = kzalloc(sizeof(*qsr), GFP_KERNEL);
>> + if (!qsr)
>> + goto out;
>> +
>> + INIT_LIST_HEAD(&qsr->lookups);
>> + INIT_LIST_HEAD(&qsr->services);
>> +
>> + INIT_WORK(&qsr->work, qsr_recv_work);
>> +
>> + qsr->recv_buf_size = sizeof(struct qrtr_ctrl_pkt);
>> + qsr->recv_buf = kzalloc(qsr->recv_buf_size, GFP_KERNEL);
>> + if (!qsr->recv_buf)
>> + goto out_qsr_free;
>> +
>> + qsr->wq = alloc_workqueue("qsr_wq", WQ_UNBOUND, 1);
>> + if (!qsr->wq)
>> + goto out_recv_buf_free;
>> +
>> + device_initialize(&qsr->dev);
>> + qsr->dev.devt = MKDEV(qsr_major, 0);
>> + qsr->dev.class = &qsr_class;
>> + dev_set_drvdata(&qsr->dev, qsr);
>> +
>> + ret = dev_set_name(&qsr->dev, QSR_NAME);
>> + if (ret) {
>> + pr_err("device name %s set failed, %d", QSR_NAME, ret);
>> + goto out_recv_buf_free;
>> + }
>> +
>> + mutex_init(&qsr->qsr_lock);
>> +
>> + ret = device_add(&qsr->dev);
>> + if (ret)
>> + goto out_wq_destroy;
>> +
>> + return ret;
>> +
>> +out_wq_destroy:
>> + destroy_workqueue(qsr->wq);
>> +out_recv_buf_free:
>> + kfree(qsr->recv_buf);
>> +out_qsr_free:
>> + kfree(qsr);
>> +out:
>> + return ret;
>> +}
>> +
>> +struct qsr_ops qsr_handle_ops = {
>> + .new_server = qsr_new_server,
>> + .new_lookup = qsr_new_lookup,
>> +};
>> +
>> +static struct socket *qsr_sock_create(void)
>> +{
>> + struct socket *sock;
>> + struct sockaddr addr;
>> + int ret;
>> +
>> + ret = sock_create_kern(&init_net, AF_QIPCRTR, SOCK_DGRAM,
>> + PF_QIPCRTR, &sock);
>> +
>> + if (ret < 0)
>> + return ERR_PTR(ret);
>> +
>> + qsr->sq.sq_family = AF_QIPCRTR;
>> + qsr->sq.sq_node = get_qrtr_local_nid();
>> + qsr->sq.sq_port = QRTR_PORT_CTRL;
>> + qsr->ops = &qsr_handle_ops;
>> +
>> + if (sock->ops->bind) {
>> + memcpy(&addr, &qsr->sq, sizeof(qsr->sq));
>> + ret = sock->ops->bind(sock, &addr, sizeof(addr));
>> + if (ret) {
>> + pr_err("Failed to bind socket address node:0x%x port:0x%x.\n",
>> + qsr->sq.sq_node, qsr->sq.sq_port);
>> + goto err_bind;
>> + }
>> + pr_debug("qsr router port binded successfully.\n");
>> + }
>> +
>> + sock->sk->sk_user_data = qsr;
>> + sock->sk->sk_data_ready = qsr_data_ready;
>> + sock->sk->sk_error_report = qsr_data_ready;
>> + sock->sk->sk_sndtimeo = HZ * 10;
>> +
>> + return sock;
>> +
>> +err_bind:
>> + sock_release(sock);
>> + return NULL;
>> +}
>> +
>> +static int qsr_release(void)
>> +{
>> + sock_release(qsr->sk);
>> +
>> + kfree(qsr->recv_buf);
>> +
>> + destroy_workqueue(qsr->wq);
>> +
>> + kfree(qsr);
>> +
>> + return 0;
>> +}
>> +
>> +static const struct file_operations qsr_fops = {
>> + .owner = THIS_MODULE,
>> +};
>> +
>> +static int __init qsr_init(void)
>> +{
>> + int ret;
>> + static const char name[] = QSR_NAME;
>> + struct cdev *cdev = NULL;
>> + dev_t rtdev;
>> +
>> + /* 1. Allocate character device region. */
>> + ret = alloc_chrdev_region(&rtdev, 0, 1, name);
>> + if (ret) {
>> + pr_err("failed to alloc chardev region\n");
>> + goto out;
>> + }
>> +
>> + /* 2. Allocate, initiate and add cdev. */
>> + ret = -ENOMEM;
>> + cdev = cdev_alloc();
>> + if (!cdev) {
>> + pr_err("failed to alloc cdev\n");
>> + goto out_unregister;
>> + }
>> +
>> + cdev->owner = THIS_MODULE;
>> + cdev->ops = &qsr_fops;
>> + kobject_set_name(&cdev->kobj, "%s", name);
>> +
>> + ret = cdev_add(cdev, rtdev, 1);
>> + if (ret)
>> + goto out_put;
>> +
>> + qsr_major = MAJOR(rtdev);
>> + qsr_cdev = cdev;
>> +
>> + /* 3. Register class. */
>> + ret = class_register(&qsr_class);
>> + if (ret) {
>> + pr_err("class_register failed for qrtr route\n");
>> + goto out_cdev_del;
>> + }
>> +
>> + /* 4. Create a qsr device. */
>> + if (qsr_dev_create())
>> + goto out_unregister_class;
>> +
>> + /* 5. Create a qrtr socket and bind it to Router port. */
>> + qsr->sk = qsr_sock_create();
>> + if (!qsr->sk)
>> + goto out_qsr_dev_del;
>> +
>> + return 0;
>> +
>> +out_qsr_dev_del:
>> + kfree(qsr);
>> +out_unregister_class:
>> + class_unregister(&qsr_class);
>> +out_cdev_del:
>> + cdev_del(qsr_cdev);
>> +out_put:
>> + kobject_put(&cdev->kobj);
>> +out_unregister:
>> + unregister_chrdev_region(rtdev, 1);
>> +out:
>> + return ret;
>> +}
>> +subsys_initcall(qsr_init);
>> +
>> +static void __exit qsr_exit(void)
>> +{
>> + qsr_release();
>> + unregister_chrdev_region(MKDEV(qsr_major, 0), 1);
>> + cdev_del(qsr_cdev);
>> + class_unregister(&qsr_class);
>> +}
>> +module_exit(qsr_exit);
>> +
>> +MODULE_AUTHOR("Wang Wenhu");
>> +MODULE_ALIAS("QRTR:" QSR_NAME);
>> +MODULE_DESCRIPTION("Qualcomm IPC Router Service Route Support");
>> +MODULE_LICENSE("GPL v2");
>> --
>> 2.17.1
>>
^ permalink raw reply [flat|nested] 8+ messages in thread
end of thread, other threads:[~2020-04-13 4:05 UTC | newest]
Thread overview: 8+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2020-04-08 10:46 [PATCH RESEND] net: qrtr: support qrtr service and lookup route Wang Wenhu
2020-04-08 21:33 ` David Miller
2020-04-09 4:18 ` 王文虎
2020-04-09 14:55 ` David Miller
2020-04-09 4:24 ` kbuild test robot
2020-04-09 19:38 ` Bjorn Andersson
2020-04-13 3:55 ` 王文虎
-- strict thread matches above, loose matches on Subject: below --
2020-04-09 2:14 kbuild test robot
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.