1 /*
2 * Copyright (c) 2015 Intel Corporation
3 * Copyright (c) 2023 Arm Limited (or its affiliates). All rights reserved.
4 *
5 * SPDX-License-Identifier: Apache-2.0
6 */
7
8 #include <zephyr/logging/log.h>
9 LOG_MODULE_DECLARE(net_zperf, CONFIG_NET_ZPERF_LOG_LEVEL);
10
11 #include <zephyr/kernel.h>
12
13 #include <zephyr/net/net_pkt.h>
14 #include <zephyr/net/udp.h>
15
16 #include "zperf_session.h"
17
18 #define SESSION_MAX CONFIG_NET_ZPERF_MAX_SESSIONS
19
20 static struct session sessions[SESSION_PROTO_END][SESSION_MAX];
21
get_free_session(const struct sockaddr * addr,enum session_proto proto)22 struct session *get_free_session(const struct sockaddr *addr,
23 enum session_proto proto)
24 {
25 struct session *ptr;
26 uint64_t oldest = 0ULL;
27 int oldest_completed_index = -1, oldest_free_index = -1;
28 int i = 0;
29
30 const struct sockaddr_in *addr4 = (const struct sockaddr_in *)addr;
31 const struct sockaddr_in6 *addr6 = (const struct sockaddr_in6 *)addr;
32
33 /* Check whether we already have an active session */
34 while (i < SESSION_MAX) {
35 ptr = &sessions[proto][i];
36
37 if (ptr->state == STATE_NULL ||
38 ptr->state == STATE_COMPLETED) {
39
40 if (oldest == 0ULL || ptr->last_time < oldest) {
41 oldest = ptr->last_time;
42
43 if (ptr->state == STATE_COMPLETED) {
44 if (oldest_completed_index < 0) {
45 oldest_completed_index = i;
46 }
47 } else {
48 /* Free session */
49 if (oldest_free_index < 0) {
50 oldest_free_index = i;
51 }
52 }
53 }
54 }
55
56 i++;
57 }
58
59 ptr = NULL;
60
61 if (oldest_free_index >= 0) {
62 ptr = &sessions[proto][oldest_free_index];
63 } else if (oldest_completed_index >= 0) {
64 ptr = &sessions[proto][oldest_completed_index];
65 }
66
67 if (ptr != NULL) {
68 if (IS_ENABLED(CONFIG_NET_IPV4) &&
69 addr->sa_family == AF_INET) {
70 ptr->port = addr4->sin_port;
71 ptr->ip.family = AF_INET;
72 net_ipaddr_copy(&ptr->ip.in_addr, &addr4->sin_addr);
73 } else if (IS_ENABLED(CONFIG_NET_IPV6) &&
74 addr->sa_family == AF_INET6) {
75 ptr->port = addr6->sin6_port;
76 ptr->ip.family = AF_INET6;
77 net_ipaddr_copy(&ptr->ip.in6_addr, &addr6->sin6_addr);
78 }
79
80 ptr->state = STATE_STARTING;
81 }
82
83 return ptr;
84 }
85
86 /* Get session from a given packet */
get_session(const struct sockaddr * addr,enum session_proto proto)87 struct session *get_session(const struct sockaddr *addr,
88 enum session_proto proto)
89 {
90 struct session *active = NULL;
91 struct session *free = NULL;
92 int i = 0;
93 const struct sockaddr_in *addr4 = (const struct sockaddr_in *)addr;
94 const struct sockaddr_in6 *addr6 = (const struct sockaddr_in6 *)addr;
95
96 if (proto != SESSION_TCP && proto != SESSION_UDP) {
97 NET_ERR("Error! unsupported proto.\n");
98 return NULL;
99 }
100
101 /* Check whether we already have an active session */
102 while (!active && i < SESSION_MAX) {
103 struct session *ptr = &sessions[proto][i];
104
105 if (IS_ENABLED(CONFIG_NET_IPV4) &&
106 addr->sa_family == AF_INET &&
107 ptr->ip.family == AF_INET &&
108 ptr->port == addr4->sin_port &&
109 net_ipv4_addr_cmp(&ptr->ip.in_addr, &addr4->sin_addr)) {
110 /* We found an active session */
111 active = ptr;
112 break;
113 }
114
115 if (IS_ENABLED(CONFIG_NET_IPV6) &&
116 addr->sa_family == AF_INET6 &&
117 ptr->ip.family == AF_INET6 &&
118 ptr->port == addr6->sin6_port &&
119 net_ipv6_addr_cmp(&ptr->ip.in6_addr, &addr6->sin6_addr)) {
120 /* We found an active session */
121 active = ptr;
122 break;
123 }
124
125 if (!free && (ptr->state == STATE_NULL ||
126 ptr->state == STATE_COMPLETED)) {
127 /* We found a free slot - just in case */
128 free = ptr;
129 }
130
131 i++;
132 }
133
134 /* If no active session then create a new one */
135 if (!active && free) {
136 active = free;
137
138 if (IS_ENABLED(CONFIG_NET_IPV4) && addr->sa_family == AF_INET) {
139 active->port = addr4->sin_port;
140 active->ip.family = AF_INET;
141 net_ipaddr_copy(&active->ip.in_addr, &addr4->sin_addr);
142 } else if (IS_ENABLED(CONFIG_NET_IPV6) &&
143 addr->sa_family == AF_INET6) {
144 active->port = addr6->sin6_port;
145 active->ip.family = AF_INET6;
146 net_ipaddr_copy(&active->ip.in6_addr, &addr6->sin6_addr);
147 }
148 }
149
150 return active;
151 }
152
zperf_reset_session_stats(struct session * session)153 void zperf_reset_session_stats(struct session *session)
154 {
155 if (!session) {
156 return;
157 }
158
159 session->counter = 0U;
160 session->start_time = 0U;
161 session->next_id = 1U;
162 session->length = 0U;
163 session->outorder = 0U;
164 session->error = 0U;
165 session->jitter = 0;
166 session->last_transit_time = 0;
167 }
168
zperf_session_foreach(enum session_proto proto,session_cb_t cb,void * user_data)169 void zperf_session_foreach(enum session_proto proto, session_cb_t cb,
170 void *user_data)
171 {
172 ARRAY_FOR_EACH(sessions[proto], i) {
173 cb(&sessions[proto][i], proto, user_data);
174 }
175 }
176
zperf_session_reset(enum session_proto proto)177 void zperf_session_reset(enum session_proto proto)
178 {
179 int i, j;
180
181 if (proto >= SESSION_PROTO_END) {
182 return;
183 }
184
185 i = (int)proto;
186
187 for (j = 0; j < SESSION_MAX; j++) {
188 sessions[i][j].state = STATE_NULL;
189 sessions[i][j].id = j;
190 zperf_reset_session_stats(&(sessions[i][j]));
191 }
192 }
193
zperf_session_init(void)194 void zperf_session_init(void)
195 {
196 int i;
197
198 for (i = 0; i < SESSION_PROTO_END; i++) {
199 zperf_session_reset(i);
200 }
201 }
202