Support packets in flight
[samplevnf.git] / VNFs / DPPD-PROX / run.c
1 /*
2 // Copyright (c) 2010-2017 Intel Corporation
3 //
4 // Licensed under the Apache License, Version 2.0 (the "License");
5 // you may not use this file except in compliance with the License.
6 // You may obtain a copy of the License at
7 //
8 //     http://www.apache.org/licenses/LICENSE-2.0
9 //
10 // Unless required by applicable law or agreed to in writing, software
11 // distributed under the License is distributed on an "AS IS" BASIS,
12 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 // See the License for the specific language governing permissions and
14 // limitations under the License.
15 */
16
17 #include <inttypes.h>
18 #include <string.h>
19
20 #include <rte_launch.h>
21 #include <rte_cycles.h>
22 #include <rte_atomic.h>
23
24 #include "run.h"
25 #include "prox_cfg.h"
26 #include "prox_port_cfg.h"
27 #include "quit.h"
28 #include "commands.h"
29 #include "main.h"
30 #include "log.h"
31 #include "display.h"
32 #include "stats.h"
33 #include "stats_cons.h"
34 #include "stats_cons_log.h"
35 #include "stats_cons_cli.h"
36
37 #include "input.h"
38 #include "input_curses.h"
39 #include "input_conn.h"
40 #include "handle_master.h"
41
42 static int needs_refresh;
43 static uint64_t update_interval;
44 static int stop_prox = 0; /* set to 1 to stop prox */
45
46 void set_update_interval(uint32_t msec)
47 {
48         update_interval = msec_to_tsc(msec);
49 }
50
51 void req_refresh(void)
52 {
53         needs_refresh = 1;
54 }
55
56 void quit(void)
57 {
58         static rte_atomic32_t already_leaving = RTE_ATOMIC32_INIT(0);
59         if (!rte_atomic32_test_and_set(&already_leaving))
60                 return;
61
62         plog_info("Leaving...\n");
63         if (lcore_cfg == NULL)
64                 exit(EXIT_SUCCESS);
65         stop_core_all(-1);
66         stop_prox = 1;
67 }
68
69 static void update_link_states(void)
70 {
71         struct prox_port_cfg *port_cfg;
72         struct rte_eth_link link;
73
74         for (uint8_t portid = 0; portid < PROX_MAX_PORTS; ++portid) {
75                 if (!prox_port_cfg[portid].active) {
76                         continue;
77                 }
78
79                 port_cfg  = &prox_port_cfg[portid];
80                 rte_eth_link_get_nowait(portid, &link);
81                 port_cfg->link_speed = link.link_speed;
82                 if (port_cfg->link_up != link.link_status) {
83                         port_cfg->link_up = link.link_status;
84                         plog_info("port %d: Link speed now %d Mbps\n", portid, link.link_speed);
85                 }
86         }
87 }
88
89 static struct stats_cons stats_cons[8];
90 static size_t n_stats_cons = 0;
91 static uint16_t stats_cons_flags = 0;
92
93 static void stats_cons_add(struct stats_cons *sc)
94 {
95         if (n_stats_cons == sizeof(stats_cons)/sizeof(stats_cons[0]))
96                 return;
97
98         stats_cons[n_stats_cons++] = *sc;
99         sc->init();
100         stats_cons_flags |= sc->flags;
101 }
102
103 static void stats_cons_notify(void)
104 {
105         for (size_t i = 0; i < n_stats_cons; ++i) {
106                 stats_cons[i].notify();
107         }
108 }
109
110 static void stats_cons_refresh(void)
111 {
112         for (size_t i = 0; i < n_stats_cons; ++i) {
113                 if (stats_cons[i].refresh)
114                         stats_cons[i].refresh();
115         }
116 }
117
118 static void stats_cons_finish(void)
119 {
120         for (size_t i = 0; i < n_stats_cons; ++i) {
121                 if (stats_cons[i].finish)
122                         stats_cons[i].finish();
123         }
124 }
125
126 static void busy_wait_until(uint64_t deadline)
127 {
128         while (rte_rdtsc() < deadline)
129                 ;
130 }
131
132 static void multiplexed_input_stats(uint64_t deadline)
133 {
134         if (deadline)
135                 input_proc_until(deadline);
136         else
137                 input_proc();
138
139         if (needs_refresh) {
140                 needs_refresh = 0;
141                 stats_cons_refresh();
142         }
143
144         if (rte_atomic32_read(&lsc)) {
145                 rte_atomic32_dec(&lsc);
146                 update_link_states();
147                 stats_cons_refresh();
148         }
149 }
150
151 static void print_warnings(void)
152 {
153         if (get_n_warnings() == -1) {
154                 plog_info("Warnings disabled\n");
155         }
156         else if (get_n_warnings() > 0) {
157                 int n_print = get_n_warnings() < 5? get_n_warnings(): 5;
158                 plog_info("Started with %d warnings, last %d warnings: \n", get_n_warnings(), n_print);
159                 for (int i = -n_print + 1; i <= 0; ++i) {
160                         plog_info("%s", get_warning(i));
161                 }
162         }
163         else {
164                 plog_info("Started without warnings\n");
165         }
166 }
167
168 /* start main loop */
169 void __attribute__((noreturn)) run(uint32_t flags)
170 {
171         uint64_t cur_tsc;
172         uint64_t next_update;
173         uint64_t stop_tsc = 0;
174         int ret = 0;
175         const uint64_t update_interval_threshold = usec_to_tsc(1);
176
177         if (flags & DSF_LISTEN_TCP)
178                 PROX_PANIC(reg_input_tcp(), "Failed to start listening on TCP port 8474: %s\n", strerror(errno));
179         if (flags & DSF_LISTEN_UDS)
180                 PROX_PANIC(reg_input_uds(), "Failed to start listening on UDS /tmp/prox.sock: %s\n", strerror(errno));
181
182         if (prox_cfg.use_stats_logger)
183                 stats_cons_add(stats_cons_log_get());
184
185         stats_init(prox_cfg.start_time, prox_cfg.duration_time);
186         stats_update(STATS_CONS_F_ALL);
187
188         switch (prox_cfg.ui) {
189         case PROX_UI_CURSES:
190                 reg_input_curses();
191                 stats_cons_add(&display);
192                 break;
193         case PROX_UI_CLI:
194                 stats_cons_add(stats_cons_cli_get());
195                 break;
196         case PROX_UI_NONE:
197         default:
198                 break;
199         }
200
201         if (flags & DSF_AUTOSTART)
202                 start_core_all(-1);
203         else
204                 stop_core_all(-1);
205
206         cur_tsc = rte_rdtsc();
207         if (prox_cfg.duration_time != 0) {
208                 stop_tsc = cur_tsc + sec_to_tsc(prox_cfg.start_time + prox_cfg.duration_time);
209         }
210
211         stats_cons_notify();
212         stats_cons_refresh();
213
214         update_interval = str_to_tsc(prox_cfg.update_interval_str);
215         next_update = cur_tsc + update_interval;
216
217         cmd_rx_tx_info();
218         print_warnings();
219
220         struct task_master *task = (struct task_master *)lcore_cfg[prox_cfg.master].tasks_all[0];
221         if (handle_ctrl_plane) {
222                 while (stop_prox == 0) {
223                         ret = 1;
224                         // Run ctrl plane for max 10 msec to let screen and keyboard updates
225                         if (prox_cfg.flags & DSF_CTRL_PLANE_ENABLED) {
226                                 uint64_t ctrl_plane_update = rte_rdtsc() + msec_to_tsc(10);
227                                 while ((ret) && (rte_rdtsc() < ctrl_plane_update))
228                                         ret = handle_ctrl_plane(lcore_cfg[prox_cfg.master].tasks_all[0], NULL, 0);
229                         }
230                         multiplexed_input_stats(0);
231                         if (rte_rdtsc() < next_update)
232                                 continue;
233                         next_update += update_interval;
234                         stats_update(stats_cons_flags);
235                         stats_cons_notify();
236
237                         if (stop_tsc && rte_rdtsc() >= stop_tsc) {
238                                 stop_prox = 1;
239                         }
240                         if ((prox_cfg.heartbeat_tsc) && (prox_cfg.heartbeat_timeout) && (rte_rdtsc() >= prox_cfg.heartbeat_tsc)) {
241                                 plog_info("Stopping to handle client as heartbeat timed out\n");
242                                 stop_core_all(-1);
243                                 stop_handling_client();
244                                 req_refresh();
245                                 prox_cfg.heartbeat_tsc = 0;
246                         }
247                 }
248         } else {
249                 while (stop_prox == 0) {
250
251                         if (update_interval < update_interval_threshold)
252                                 busy_wait_until(next_update);
253                         else
254                                 multiplexed_input_stats(next_update);
255
256                         next_update += update_interval;
257
258                         stats_update(stats_cons_flags);
259                         stats_cons_notify();
260
261                         if (stop_tsc && rte_rdtsc() >= stop_tsc) {
262                                 stop_prox = 1;
263                         }
264                         if ((prox_cfg.heartbeat_tsc) && (prox_cfg.heartbeat_timeout) && (rte_rdtsc() >= prox_cfg.heartbeat_tsc)) {
265                                 plog_info("Stopping to handle client as heartbeat timed out\n");
266                                 stop_core_all(-1);
267                                 stop_handling_client();
268                                 req_refresh();
269                                 prox_cfg.heartbeat_tsc = 0;
270                         }
271                 }
272         }
273
274         stats_cons_finish();
275
276         if (prox_cfg.flags & DSF_WAIT_ON_QUIT) {
277                 stop_core_all(-1);
278         }
279
280         if (prox_cfg.logbuf) {
281                 file_print(prox_cfg.logbuf);
282         }
283
284         display_end();
285         exit(EXIT_SUCCESS);
286 }