Merge "[l2l3 stack] implements new nd state machine & nd buffering"
[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
41 static int needs_refresh;
42 static uint64_t update_interval;
43 static int stop_prox = 0; /* set to 1 to stop prox */
44
45 void set_update_interval(uint32_t msec)
46 {
47         update_interval = msec_to_tsc(msec);
48 }
49
50 void req_refresh(void)
51 {
52         needs_refresh = 1;
53 }
54
55 void quit(void)
56 {
57         static rte_atomic32_t already_leaving = RTE_ATOMIC32_INIT(0);
58         if (!rte_atomic32_test_and_set(&already_leaving))
59                 return;
60
61         plog_info("Leaving...\n");
62         if (lcore_cfg == NULL)
63                 exit(EXIT_SUCCESS);
64         stop_core_all(-1);
65         stop_prox = 1;
66 }
67
68 static void update_link_states(void)
69 {
70         struct prox_port_cfg *port_cfg;
71         struct rte_eth_link link;
72
73         for (uint8_t portid = 0; portid < PROX_MAX_PORTS; ++portid) {
74                 if (!prox_port_cfg[portid].active) {
75                         continue;
76                 }
77
78                 port_cfg  = &prox_port_cfg[portid];
79                 rte_eth_link_get_nowait(portid, &link);
80                 port_cfg->link_up = link.link_status;
81                 port_cfg->link_speed = link.link_speed;
82         }
83 }
84
85 static struct stats_cons stats_cons[8];
86 static size_t n_stats_cons = 0;
87 static uint16_t stats_cons_flags = 0;
88
89 static void stats_cons_add(struct stats_cons *sc)
90 {
91         if (n_stats_cons == sizeof(stats_cons)/sizeof(stats_cons[0]))
92                 return;
93
94         stats_cons[n_stats_cons++] = *sc;
95         sc->init();
96         stats_cons_flags |= sc->flags;
97 }
98
99 static void stats_cons_notify(void)
100 {
101         for (size_t i = 0; i < n_stats_cons; ++i) {
102                 stats_cons[i].notify();
103         }
104 }
105
106 static void stats_cons_refresh(void)
107 {
108         for (size_t i = 0; i < n_stats_cons; ++i) {
109                 if (stats_cons[i].refresh)
110                         stats_cons[i].refresh();
111         }
112 }
113
114 static void stats_cons_finish(void)
115 {
116         for (size_t i = 0; i < n_stats_cons; ++i) {
117                 if (stats_cons[i].finish)
118                         stats_cons[i].finish();
119         }
120 }
121
122 static void busy_wait_until(uint64_t deadline)
123 {
124         while (rte_rdtsc() < deadline)
125                 ;
126 }
127
128 static void multiplexed_input_stats(uint64_t deadline)
129 {
130         input_proc_until(deadline);
131
132         if (needs_refresh) {
133                 needs_refresh = 0;
134                 stats_cons_refresh();
135         }
136
137         if (rte_atomic32_read(&lsc)) {
138                 rte_atomic32_dec(&lsc);
139                 update_link_states();
140                 stats_cons_refresh();
141         }
142 }
143
144 static void print_warnings(void)
145 {
146         if (get_n_warnings() == -1) {
147                 plog_info("Warnings disabled\n");
148         }
149         else if (get_n_warnings() > 0) {
150                 int n_print = get_n_warnings() < 5? get_n_warnings(): 5;
151                 plog_info("Started with %d warnings, last %d warnings: \n", get_n_warnings(), n_print);
152                 for (int i = -n_print + 1; i <= 0; ++i) {
153                         plog_info("%s", get_warning(i));
154                 }
155         }
156         else {
157                 plog_info("Started without warnings\n");
158         }
159 }
160
161 /* start main loop */
162 void __attribute__((noreturn)) run(uint32_t flags)
163 {
164         uint64_t cur_tsc;
165         uint64_t next_update;
166         uint64_t stop_tsc = 0;
167         const uint64_t update_interval_threshold = usec_to_tsc(1);
168
169         if (flags & DSF_LISTEN_TCP)
170                 PROX_PANIC(reg_input_tcp(), "Failed to start listening on TCP port 8474: %s\n", strerror(errno));
171         if (flags & DSF_LISTEN_UDS)
172                 PROX_PANIC(reg_input_uds(), "Failed to start listening on UDS /tmp/prox.sock: %s\n", strerror(errno));
173
174         if (prox_cfg.use_stats_logger)
175                 stats_cons_add(stats_cons_log_get());
176
177         stats_init(prox_cfg.start_time, prox_cfg.duration_time);
178         stats_update(STATS_CONS_F_ALL);
179
180         switch (prox_cfg.ui) {
181         case PROX_UI_CURSES:
182                 reg_input_curses();
183                 stats_cons_add(&display);
184                 break;
185         case PROX_UI_CLI:
186                 stats_cons_add(stats_cons_cli_get());
187                 break;
188         case PROX_UI_NONE:
189         default:
190                 break;
191         }
192
193         if (flags & DSF_AUTOSTART)
194                 start_core_all(-1);
195         else
196                 stop_core_all(-1);
197
198         cur_tsc = rte_rdtsc();
199         if (prox_cfg.duration_time != 0) {
200                 stop_tsc = cur_tsc + sec_to_tsc(prox_cfg.start_time + prox_cfg.duration_time);
201         }
202
203         stats_cons_notify();
204         stats_cons_refresh();
205
206         update_interval = str_to_tsc(prox_cfg.update_interval_str);
207         next_update = cur_tsc + update_interval;
208
209         cmd_rx_tx_info();
210         print_warnings();
211
212         while (stop_prox == 0) {
213
214                 if (update_interval < update_interval_threshold)
215                         busy_wait_until(next_update);
216                 else
217                         multiplexed_input_stats(next_update);
218
219                 next_update += update_interval;
220
221                 stats_update(stats_cons_flags);
222                 stats_cons_notify();
223
224                 if (stop_tsc && rte_rdtsc() >= stop_tsc) {
225                         stop_prox = 1;
226                 }
227         }
228
229         stats_cons_finish();
230
231         if (prox_cfg.flags & DSF_WAIT_ON_QUIT) {
232                 stop_core_all(-1);
233         }
234
235         if (prox_cfg.logbuf) {
236                 file_print(prox_cfg.logbuf);
237         }
238
239         display_end();
240         exit(EXIT_SUCCESS);
241 }