1 /*
2  * Copyright (C) 2022 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 #include "pcb.h"
17 #ifdef FILLP_SUPPORT_GSO
18 #include "check_gso_support.h"
19 #endif
20 #ifdef FILLP_LINUX
21 #include <netinet/udp.h>
22 #endif
23 #include "res.h"
24 #include "fillp_algorithm.h"
25 #include "spunge.h"
26 #include "fillp_mgt_msg_log.h"
27 
28 #ifdef __cplusplus
29 extern "C" {
30 #endif
31 
SpungePcbRecv(void * argConn,void ** buf,FILLP_INT count)32 static FILLP_INT SpungePcbRecv(void *argConn, void **buf, FILLP_INT count)
33 {
34     struct FtNetconn *conn = (struct FtNetconn *)argConn;
35     struct FtSocket *sock = (struct FtSocket *)conn->sock;
36     FillpErrorType err = FillpQueuePush(conn->pcb->fpcb.recv.recvBox, buf, FILLP_TRUE, (FILLP_UINT)count);
37     if (err) {
38         FILLP_LOGERR("SpungePcbRecv: FillpQueuePush failed. sockId =%d", sock->index);
39 
40         return err;
41     }
42 
43 #ifdef SOCK_RECV_SEM
44     {
45         FILLP_INT tmp = count;
46 
47         while (tmp--) {
48             (void)SYS_ARCH_SEM_POST(&SOCK_GET_RECVSEM(sock));
49         }
50     }
51 #endif /* SOCK_RECV_SEM */
52 
53     SpungeEpollEventCallback(sock, SPUNGE_EPOLLIN, count);
54 
55     return ERR_OK;
56 }
57 
SpungePcbSend(void * arg,FILLP_CONST char * buf,FILLP_INT size,void * ppcb)58 static FILLP_INT SpungePcbSend(void *arg, FILLP_CONST char *buf,
59     FILLP_INT size, void *ppcb)
60 {
61     struct FtNetconn *conn = (struct FtNetconn *)arg;
62     struct SpungePcb *pcb = (struct SpungePcb *)ppcb;
63     struct SockOsSocket *osSock = NETCONN_GET_OSSOCK(conn, SPUNGE_GET_CUR_INSTANCE()->instIndex);
64 
65     if (!OS_SOCK_OPS_FUNC_VALID(osSock, send)) {
66         return -1;
67     }
68 
69     FILLP_PKT_SIMPLE_LOG(((struct FtSocket *)conn->sock)->index,
70         (FILLP_CONST struct FillpPktHead *)buf, FILLP_DIRECTION_TX);
71 
72     if (size != (FILLP_INT) osSock->ioSock->ops->send(osSock->ioSock,
73                                                       buf,
74                                                       (FILLP_SIZE_T)((FILLP_UINT)size),
75                                                       (struct sockaddr *)&pcb->remoteAddr,
76                                                       pcb->addrLen)) {
77         return -1;
78     } else {
79         return size;
80     }
81 }
82 
83 #ifdef FILLP_SUPPORT_GSO
84 #ifndef UDP_MAX_SEG
85 #define UDP_MAX_SEG 44
86 #endif
SendUdpSegmentCmsg(struct cmsghdr * cm)87 void SendUdpSegmentCmsg(struct cmsghdr *cm)
88 {
89     FILLP_UINT16 *valp = FILLP_NULL_PTR;
90     cm->cmsg_level = SOL_UDP;
91     cm->cmsg_type = UDP_SEGMENT;
92     cm->cmsg_len = CMSG_LEN(sizeof(FILLP_UINT16));
93     valp = (FILLP_UINT16 *)(void *)CMSG_DATA(cm);
94     *valp = CFG_MSS;
95 }
96 
SpungePcbSendmsgInner(struct FtNetconn * conn,struct SpungePcb * spcb,SysIoUdpSock * udpSock,FILLP_INT size)97 static FILLP_INT SpungePcbSendmsgInner(struct FtNetconn *conn, struct SpungePcb *spcb,
98     SysIoUdpSock *udpSock, FILLP_INT size)
99 {
100     struct msghdr mh;
101     FILLP_CHAR control[CMSG_SPACE(sizeof(FILLP_UINT16))] = {0};
102     int ret;
103 
104     if (conn->iovCount == 0) {
105         return 0;
106     }
107 
108     mh.msg_name = (struct sockaddr *)&spcb->remoteAddr;
109     mh.msg_namelen = spcb->addrLen;
110     mh.msg_iov = conn->sendIov;
111     mh.msg_iovlen = conn->iovCount;
112     mh.msg_flags = 0;
113     if (conn->iovCount == 1) {
114         mh.msg_control = FILLP_NULL_PTR;
115         mh.msg_controllen = 0;
116     } else {
117         mh.msg_control = control;
118         mh.msg_controllen = sizeof(control);
119         SendUdpSegmentCmsg(CMSG_FIRSTHDR(&mh));
120     }
121     if (sendmsg(udpSock->udpSock, &mh, 0) < 0) {
122         ret = -1;
123     } else {
124         ret = size;
125     }
126     FILLP_LOGDTL("gso send %zu", conn->iovCount);
127 
128     if (ret == -1 && errno == EIO) {
129         FILLP_INT sentFail = 0;
130         for (size_t i = 0; i < conn->iovCount; i++) {
131             /* EIO may be caused by netdevices not support checksum offload, so kernel gso return EIO.
132              * As kernel udp gso suggested, fallback to send.
133              */
134             ret = spcb->fpcb.sendFunc(conn, conn->sendIov[i].iov_base, conn->sendIov[i].iov_len, spcb);
135             if (ret <= 0) {
136                 sentFail = 1;
137                 break;
138             }
139         }
140 
141         if (sentFail == 0) {
142             ret = size;
143         } else {
144             ret = -1;
145         }
146         FILLP_LOGERR("fallback to send, ret %d", ret);
147         spcb->fpcb.sendmsgEio = FILLP_TRUE;
148     }
149     conn->iovCount = 0;
150     return ret;
151 }
152 
SpungePcbSendmsg(void * arg,FILLP_CONST char * buf,FILLP_INT size,void * pcb)153 FILLP_INT SpungePcbSendmsg(void *arg, FILLP_CONST char *buf, FILLP_INT size, void *pcb)
154 {
155     struct FtNetconn *conn = FILLP_NULL_PTR;
156     struct SockOsSocket *osSock = FILLP_NULL_PTR;
157     struct FillpPcb *fpcb = (struct FillpPcb *)pcb;
158     struct SpungePcb *spcb = (struct SpungePcb *)fpcb->spcb;
159     FILLP_UINT16 cfgMss = CFG_MSS;
160     FILLP_INT ret;
161     SysIoUdpSock *udpSock = FILLP_NULL_PTR;
162     FILLP_BOOL send = FILLP_FALSE;
163 
164     if (buf == FILLP_NULL_PTR) {
165         conn = (struct FtNetconn *)spcb->conn;
166     } else {
167         conn = (struct FtNetconn *)arg;
168     }
169     osSock = NETCONN_GET_OSSOCK(conn, SPUNGE_GET_CUR_INSTANCE()->instIndex);
170     if (osSock == FILLP_NULL_PTR) {
171         return -1;
172     }
173 
174     udpSock = (SysIoUdpSock *)osSock->ioSock;
175 
176     if (buf == FILLP_NULL_PTR) {
177         ret = SpungePcbSendmsgInner(conn, spcb, udpSock, size);
178         return ret;
179     }
180 
181     if (size < cfgMss) {
182         send = FILLP_TRUE;
183     }
184 
185     conn->sendIov[conn->iovCount].iov_len = (size_t)(FILLP_UINT)size;
186     conn->sendIov[conn->iovCount].iov_base = (void *)buf;
187     conn->iovCount++;
188 
189     if ((conn->iovCount < UDP_MAX_SEG) && (fpcb->isLast == FILLP_FALSE) && send == FILLP_FALSE) {
190         return size;
191     }
192     ret = SpungePcbSendmsgInner(conn, spcb, udpSock, size);
193     return ret;
194 }
195 #endif
SpcbAddPcbToSpinst(struct SpungeInstance * inst,struct SpungePcb * pcb)196 void SpcbAddPcbToSpinst(struct SpungeInstance *inst, struct SpungePcb *pcb)
197 {
198     SpinstAddToPcbList(inst, &pcb->udpNode);
199 }
200 
SpcbDeleteFromSpinst(struct SpungeInstance * inst,struct SpungePcb * pcb)201 void SpcbDeleteFromSpinst(struct SpungeInstance *inst, struct SpungePcb *pcb)
202 {
203     SpinstDeleteFromPcbList(inst, &pcb->udpNode);
204 }
205 
SpungePcbNew(void * argConn,struct SpungeInstance * inst)206 struct SpungePcb *SpungePcbNew(void *argConn, struct SpungeInstance *inst)
207 {
208     struct SpungePcb *pcb = (struct SpungePcb *)SpungeAlloc(1, sizeof(struct SpungePcb), SPUNGE_ALLOC_TYPE_CALLOC);
209     if (pcb == FILLP_NULL_PTR) {
210         FILLP_LOGERR("Failed allocate memory for spunge_pcb");
211         return FILLP_NULL_PTR;
212     }
213 
214     pcb->conn = argConn;
215     pcb->fpcb.spcb = (void *)pcb;
216     pcb->fpcb.resInited = 0;
217 
218     pcb->fpcb.mpRecvSize = 0;
219     pcb->fpcb.mpSendSize = 0;
220     pcb->fpcb.clientCookiePreserveTime = 0;
221     pcb->fpcb.pcbInst = inst;
222     pcb->fpcb.localUniqueId = 0;
223     pcb->fpcb.peerUniqueId = 0;
224     pcb->fpcb.send.pktStartNum = FILLP_CRYPTO_RAND();
225     pcb->fpcb.send.seqStartNum = FILLP_CRYPTO_RAND();
226 
227     pcb->rateControl.recv.curMaxRateLimitation = 0;
228     pcb->rateControl.recv.weight = 0;
229 
230     pcb->rateControl.send.curMaxRateLimitation = 0;
231     pcb->rateControl.send.weight = 0;
232 
233     pcb->fpcb.pktSize = (FILLP_MAX_PKT_SIZE - FILLP_HLEN);
234     pcb->fpcb.recvFunc = SpungePcbRecv;
235     pcb->fpcb.sendFunc = SpungePcbSend;
236 #ifdef FILLP_SUPPORT_GSO
237     pcb->fpcb.sendmsgFunc = SpungePcbSendmsg;
238     (void)memset_s(pcb->devName, IFNAMESIZE, 0, IFNAMESIZE);
239     pcb->fpcb.sendmsgEio = FILLP_FALSE;
240 #endif
241     pcb->fpcb.isFinAckReceived = FILLP_FALSE;
242     SpcbAddPcbToSpinst(inst, pcb);
243     return pcb;
244 }
245 
SpungePcbSetSendCacheSize(struct SpungePcb * pcb,FILLP_UINT32 cacheSize)246 void SpungePcbSetSendCacheSize(struct SpungePcb *pcb, FILLP_UINT32 cacheSize)
247 {
248     pcb->fpcb.mpSendSize = cacheSize;
249 }
250 
SpungePcbSetRecvCacheSize(struct SpungePcb * pcb,FILLP_UINT32 cacheSize)251 void SpungePcbSetRecvCacheSize(struct SpungePcb *pcb, FILLP_UINT32 cacheSize)
252 {
253     pcb->fpcb.mpRecvSize = cacheSize;
254 }
255 
SpungePcbSetPktSize(struct SpungePcb * pcb,FILLP_UINT32 pktSize)256 void SpungePcbSetPktSize(struct SpungePcb *pcb, FILLP_UINT32 pktSize)
257 {
258     pcb->fpcb.pktSize = pktSize;
259 }
260 
SpungePcbSetOppositeRate(struct SpungePcb * pcb,FILLP_UINT32 rate)261 void SpungePcbSetOppositeRate(struct SpungePcb *pcb, FILLP_UINT32 rate)
262 {
263     pcb->fpcb.recv.oppositeSetRate = rate;
264 }
265 
SpungePcbSetSlowStart(struct SpungePcb * pcb,FILLP_BOOL slowStart)266 void SpungePcbSetSlowStart(struct SpungePcb *pcb, FILLP_BOOL slowStart)
267 {
268     pcb->fpcb.send.slowStart = slowStart;
269 }
270 
SpungePcbSetPackInterval(struct SpungePcb * pcb,FILLP_UINT32 interval)271 void SpungePcbSetPackInterval(struct SpungePcb *pcb, FILLP_UINT32 interval)
272 {
273     pcb->fpcb.statistics.pack.packInterval = interval;
274     pcb->fpcb.packTimerNode.interval = interval;
275     pcb->fpcb.FcTimerNode.interval = interval;
276 }
277 
SpungePcbSetAddrType(struct SpungePcb * pcb,FILLP_UINT16 addrType)278 void SpungePcbSetAddrType(struct SpungePcb *pcb, FILLP_UINT16 addrType)
279 {
280     pcb->addrType = addrType;
281 }
282 
SpungePcbSetLocalPort(struct SpungePcb * pcb,FILLP_INT port)283 void SpungePcbSetLocalPort(struct SpungePcb *pcb, FILLP_INT port)
284 {
285     pcb->localPort = port;
286 }
287 
SpungePcbSetDirectlySend(struct SpungePcb * pcb,FILLP_INT directlySend)288 void SpungePcbSetDirectlySend(struct SpungePcb *pcb, FILLP_INT directlySend)
289 {
290     pcb->fpcb.send.directlySend = directlySend;
291 }
292 
SpungePcbRemove(struct SpungePcb * pcb)293 void SpungePcbRemove(struct SpungePcb *pcb)
294 {
295     struct FtNetconn *conn = FILLP_NULL_PTR;
296     struct SockOsSocket *osSock = FILLP_NULL_PTR;
297     if (pcb == FILLP_NULL_PTR) {
298         FILLP_LOGERR("SpungePcbRemove: Invalid parameters passed");
299         return;
300     }
301 
302     conn = (struct FtNetconn *)pcb->conn;
303     SpcbDeleteFromSpinst(pcb->fpcb.pcbInst, pcb);
304     FillpRemovePcb(&pcb->fpcb);
305     if (conn != FILLP_NULL_PTR) {
306         osSock = NETCONN_GET_OSSOCK(conn, SPUNGE_GET_CUR_INSTANCE()->instIndex);
307         if (OS_SOCK_OPS_FUNC_VALID(osSock, removePcb)) {
308             // If alloc sock fails, the free code will go to here, sock->netconn->osSocket will be null
309             osSock->ioSock->ops->removePcb(osSock->ioSock, conn->pcb);
310         }
311     }
312 
313     SpungeFree(pcb, SPUNGE_ALLOC_TYPE_CALLOC);
314 }
315 
316 #ifdef __cplusplus
317 }
318 #endif
319