net: qrtr: Add socket mode optimization

A remote endpoint should not need to know when a client socket is freed
if the socket never established commnication with the endpoint. Add a
mode to keep track of which endpoints a socket communicates with.

There are three modes a socket can be in:
	INIT   - Socket has not sent anything or only local messages,
		 only send client close to local services.

	SINGLE - Socket has sent messages to a single ept, send event
		 to this single ept.

	MULTI  - Socket has sent messages to multiple epts, broadcast
		 release of this socket.

Server state changes should be broadcast throughout the system. Change
the ipc state of a port when it sends a NEW SERVER control packet. This
ensures the DEL CLIENT control packet is propagated correctly for
servers.

Change-Id: I416742cff598bf7aa9da2baa2e86a53b18367870
Signed-off-by: Chris Lew <quic_clew@quicinc.com>
This commit is contained in:
Chris Lew 2022-10-03 09:57:24 -07:00
parent a0f46809c5
commit cc60f7fdd8

View File

@ -24,6 +24,10 @@
#define QRTR_EPH_PORT_RANGE \
XA_LIMIT(QRTR_MIN_EPH_SOCKET, QRTR_MAX_EPH_SOCKET)
/* qrtr socket states */
#define QRTR_STATE_MULTI -2
#define QRTR_STATE_INIT -1
/**
* struct qrtr_hdr_v1 - (I|R)PCrouter packet header version 1
* @version: protocol version
@ -90,6 +94,8 @@ struct qrtr_sock {
struct sock sk;
struct sockaddr_qrtr us;
struct sockaddr_qrtr peer;
int state;
};
static inline struct qrtr_sock *qrtr_sk(struct sock *sk)
@ -688,29 +694,60 @@ static void qrtr_port_put(struct qrtr_sock *ipc)
sock_put(&ipc->sk);
}
/* Remove port assignment. */
static void qrtr_port_remove(struct qrtr_sock *ipc)
static void qrtr_send_del_client(struct qrtr_sock *ipc)
{
struct qrtr_ctrl_pkt *pkt;
struct sk_buff *skb;
int port = ipc->us.sq_port;
struct sockaddr_qrtr to;
struct qrtr_node *node;
struct sk_buff *skbn;
struct sk_buff *skb;
int type = QRTR_TYPE_DEL_CLIENT;
skb = qrtr_alloc_ctrl_packet(&pkt, GFP_KERNEL);
if (!skb)
return;
to.sq_family = AF_QIPCRTR;
to.sq_node = QRTR_NODE_BCAST;
to.sq_port = QRTR_PORT_CTRL;
skb = qrtr_alloc_ctrl_packet(&pkt, GFP_KERNEL);
if (skb) {
pkt->cmd = cpu_to_le32(QRTR_TYPE_DEL_CLIENT);
pkt->client.node = cpu_to_le32(ipc->us.sq_node);
pkt->client.port = cpu_to_le32(ipc->us.sq_port);
pkt->cmd = cpu_to_le32(QRTR_TYPE_DEL_CLIENT);
pkt->client.node = cpu_to_le32(ipc->us.sq_node);
pkt->client.port = cpu_to_le32(ipc->us.sq_port);
skb_set_owner_w(skb, &ipc->sk);
qrtr_bcast_enqueue(NULL, skb, QRTR_TYPE_DEL_CLIENT, &ipc->us,
&to);
skb_set_owner_w(skb, &ipc->sk);
if (ipc->state == QRTR_STATE_MULTI) {
qrtr_bcast_enqueue(NULL, skb, type, &ipc->us, &to);
return;
}
if (ipc->state > QRTR_STATE_INIT) {
node = qrtr_node_lookup(ipc->state);
if (!node)
goto exit;
skbn = skb_clone(skb, GFP_KERNEL);
if (!skbn) {
qrtr_node_release(node);
goto exit;
}
skb_set_owner_w(skbn, &ipc->sk);
qrtr_node_enqueue(node, skbn, type, &ipc->us, &to);
qrtr_node_release(node);
}
exit:
qrtr_local_enqueue(NULL, skb, type, &ipc->us, &to);
}
/* Remove port assignment. */
static void qrtr_port_remove(struct qrtr_sock *ipc)
{
int port = ipc->us.sq_port;
qrtr_send_del_client(ipc);
if (port == QRTR_PORT_CTRL)
port = 0;
@ -963,6 +1000,11 @@ static int qrtr_sendmsg(struct socket *sock, struct msghdr *msg, size_t len)
return -ECONNRESET;
}
enqueue_fn = qrtr_node_enqueue;
if (ipc->state > QRTR_STATE_INIT && ipc->state != node->nid)
ipc->state = QRTR_STATE_MULTI;
else if (ipc->state == QRTR_STATE_INIT)
ipc->state = node->nid;
}
plen = (len + 3) & ~3;
@ -981,7 +1023,8 @@ static int qrtr_sendmsg(struct socket *sock, struct msghdr *msg, size_t len)
goto out_node;
}
if (ipc->us.sq_port == QRTR_PORT_CTRL) {
if (ipc->us.sq_port == QRTR_PORT_CTRL ||
addr->sq_port == QRTR_PORT_CTRL) {
if (len < 4) {
rc = -EINVAL;
kfree_skb(skb);
@ -993,6 +1036,9 @@ static int qrtr_sendmsg(struct socket *sock, struct msghdr *msg, size_t len)
}
type = le32_to_cpu(qrtr_type);
if (addr->sq_port == QRTR_PORT_CTRL && type == QRTR_TYPE_NEW_SERVER)
ipc->state = QRTR_STATE_MULTI;
rc = enqueue_fn(node, skb, type, &ipc->us, addr);
if (rc >= 0)
rc = len;
@ -1284,6 +1330,7 @@ static int qrtr_create(struct net *net, struct socket *sock,
ipc->us.sq_family = AF_QIPCRTR;
ipc->us.sq_node = qrtr_local_nid;
ipc->us.sq_port = 0;
ipc->state = QRTR_STATE_INIT;
return 0;
}