Line data Source code
1 : /*
2 : * vif.c -- 'vrouter' interface utility
3 : *
4 : * Copyright (c) 2013 Juniper Networks, Inc. All rights reserved.
5 : * Copyright Contributors to the OpenSDN project
6 : */
7 : #include <stdio.h>
8 : #include <assert.h>
9 : #include <fcntl.h>
10 : #include <unistd.h>
11 : #include <string.h>
12 : #include <stdlib.h>
13 : #include <inttypes.h>
14 : #include <getopt.h>
15 : #include <stdbool.h>
16 : #include <ctype.h>
17 : #include <time.h>
18 :
19 : #include "vr_os.h"
20 :
21 : #include <sys/types.h>
22 : #include <sys/socket.h>
23 : #include <sys/ioctl.h>
24 :
25 : #if defined(__linux__)
26 : #include <asm/types.h>
27 :
28 : #include <linux/netlink.h>
29 : #include <linux/rtnetlink.h>
30 : #include <linux/if_ether.h>
31 : #endif
32 :
33 : #if defined(__linux__)
34 : #include <net/if.h>
35 : #include <net/ethernet.h>
36 : #include <netinet/ether.h>
37 : #endif
38 :
39 : #include <termios.h>
40 : #include <sys/select.h>
41 : #include <sys/time.h>
42 :
43 : #include "vr_types.h"
44 : #include "vr_message.h"
45 : #include "vr_packet.h"
46 : #include "vr_interface.h"
47 : #include "vhost.h"
48 : #include "vr_genetlink.h"
49 : #include "nl_util.h"
50 : #include "ini_parser.h"
51 :
52 :
53 : #define LISTING_NUM_OF_LINE 3
54 : #define MAX_OUTPUT_IF 32
55 :
56 : #define SET_TIMEOUT_MS 1000
57 : #define CORRECT_ERROR_CNT(cur_error_cnt_ptr, prev_error_cnt_ptr) \
58 : if (*((uint64_t *) cur_error_cnt_ptr) < *((uint64_t *) prev_error_cnt_ptr)) { \
59 : *((uint64_t *) cur_error_cnt_ptr) = *((uint64_t *) prev_error_cnt_ptr); }
60 :
61 : #define COMPUTE_DIFFERENCE(new, old, counter, diff_time_ms) \
62 : new->counter = ((new->counter - old->counter) * 1000)/diff_time_ms
63 :
64 : #define VHOST_TYPE_STRING "vhost"
65 : #define AGENT_TYPE_STRING "agent"
66 : #define PHYSICAL_TYPE_STRING "physical"
67 : #define VIRTUAL_TYPE_STRING "virtual"
68 : #define XEN_LL_TYPE_STRING "xenll"
69 : #define GATEWAY_TYPE_STRING "gateway"
70 : #define VIRTUAL_VLAN_TYPE_STRING "virtual-vlan"
71 : #define STATS_TYPE_STRING "stats"
72 : #define MONITORING_TYPE_STRING "monitoring"
73 :
74 : #define ETH_TRANSPORT_STRING "eth"
75 : #define PMD_TRASPORT_STRING "pmd"
76 : #define SOCKET_TRANSPORT_STRING "socket"
77 : #define VIRTUAL_TRANSPORT_STRING "virtual"
78 :
79 : static struct nl_client *cl;
80 : static char flag_string[64], if_name[IFNAMSIZ];
81 : static int if_kindex = -1, vrf_id, vr_ifindex = -1;
82 : static int if_pmdindex = -1, vif_index = -1;
83 : static bool need_xconnect_if = false;
84 : static bool need_vif_id = false;
85 : static int if_xconnect_kindex[VR_MAX_PHY_INF] = {-1, -1, -1};
86 : static short vlan_id = -1;
87 : static int vr_ifflags;
88 : static unsigned int core = (unsigned)-1;
89 : static int8_t vr_transport = 0;
90 :
91 : static int add_set, create_set, get_set, list_set;
92 : static int kindex_set, type_set, transport_set, help_set, set_set, vlan_set, dhcp_set;
93 : static int vrf_set, mac_set, delete_set, policy_set, pmd_set, vindex_set, pci_set;
94 : static int xconnect_set, vif_set, vhost_phys_set, core_set, rate_set, drop_set;
95 : static int sock_dir_set, clear_stats_set;
96 :
97 : static unsigned int vr_op, vr_if_type;
98 : static bool dump_pending = false;
99 : static bool vr_vrf_assign_dump = false;
100 : static int dump_marker = -1, var_marker = -1;
101 :
102 : static int platform;
103 :
104 : static int8_t vr_ifmac[6];
105 : static struct ether_addr *mac_opt;
106 :
107 : static vr_interface_req prev_req[VR_MAX_INTERFACES];
108 : static struct timeval last_time;
109 :
110 :
111 : static bool first_rate_iter = false;
112 :
113 :
114 : /*
115 : * How many times we partially ignore function call vr_interface_req_process.
116 : * For more information please read comment description for function:
117 : * vr_interface_req_process
118 : */
119 : static int ignore_number_interface = 0;
120 :
121 : /*
122 : * How many interfaces we will print/count in rate statistics
123 : */
124 : static int print_number_interface = 0;
125 :
126 : static void Usage(void);
127 : static void usage_internal(const char *msg);
128 : static void list_header_print(void);
129 : static void list_get_print(vr_interface_req *);
130 : static void list_rate_print(vr_interface_req *);
131 : static void rate_process(vr_interface_req *req, vr_interface_req *prev_req);
132 : static void rate_stats_diff(vr_interface_req *, vr_interface_req *);
133 : static void rate_stats(struct nl_client *, unsigned int);
134 : static int is_stdin_hit();
135 : static int is_number(const char *nptr);
136 :
137 : static struct vr_util_flags flag_metadata[] = {
138 : {VIF_FLAG_POLICY_ENABLED, "P", "Policy" },
139 : {VIF_FLAG_XCONNECT, "X", "Cross Connect" },
140 : {VIF_FLAG_SERVICE_IF, "S", "Service Chain" },
141 : {VIF_FLAG_MIRROR_RX, "Mr", "Receive Mirror" },
142 : {VIF_FLAG_MIRROR_TX, "Mt", "Transmit Mirror" },
143 : {VIF_FLAG_TX_CSUM_OFFLOAD, "Tc", "Transmit Checksum Offload"},
144 : {VIF_FLAG_L3_ENABLED, "L3", "Layer 3" },
145 : {VIF_FLAG_L2_ENABLED, "L2", "Layer 2" },
146 : {VIF_FLAG_DHCP_ENABLED, "D", "DHCP" },
147 : {VIF_FLAG_VHOST_PHYS, "Vp", "Vhost Physical" },
148 : {VIF_FLAG_PROMISCOUS, "Pr", "Promiscuous" },
149 : {VIF_FLAG_NATIVE_VLAN_TAG, "Vnt", "Native Vlan Tagged"},
150 : {VIF_FLAG_NO_ARP_PROXY, "Mnp", "No MAC Proxy" },
151 : {VIF_FLAG_PMD, "Dpdk", "DPDK PMD Interface"},
152 : {VIF_FLAG_FILTERING_OFFLOAD,"Rfl", "Receive Filtering Offload"},
153 : {VIF_FLAG_MONITORED, "Mon", "Interface is Monitored"},
154 : {VIF_FLAG_UNKNOWN_UC_FLOOD, "Uuf", "Unknown Unicast Flood"},
155 : {VIF_FLAG_VLAN_OFFLOAD, "Vof", "VLAN insert/strip offload"},
156 : {VIF_FLAG_DROP_NEW_FLOWS, "Df", "Drop New Flows"},
157 : {VIF_FLAG_MAC_LEARN, "L", "MAC Learning Enabled"},
158 : {VIF_FLAG_MAC_PROXY, "Proxy", "MAC Requests Proxied Always"},
159 : {VIF_FLAG_ETREE_ROOT, "Er", "Etree Root"},
160 : {VIF_FLAG_MIRROR_NOTAG, "Mn", "Mirror without Vlan Tag"},
161 : {VIF_FLAG_HBS_LEFT, "HbsL", "HBS Left Intf"},
162 : {VIF_FLAG_HBS_RIGHT, "HbsR", "HBS Right Intf"},
163 : {VIF_FLAG_IGMP_ENABLED, "Ig", "Igmp Trap Enabled"},
164 : {VIF_FLAG_MAC_IP_LEARNING, "Ml", "MAC-IP Learning Enabled"},
165 : };
166 :
167 : static char *
168 3 : vr_get_if_type_string(int t)
169 : {
170 3 : switch (t) {
171 3 : case VIF_TYPE_HOST:
172 3 : return "Host";
173 0 : case VIF_TYPE_AGENT:
174 0 : return "Agent";
175 0 : case VIF_TYPE_PHYSICAL:
176 0 : return "Physical";
177 0 : case VIF_TYPE_VIRTUAL:
178 0 : return "Virtual";
179 0 : case VIF_TYPE_XEN_LL_HOST:
180 0 : return "XenLL";
181 0 : case VIF_TYPE_GATEWAY:
182 0 : return "Gateway";
183 0 : case VIF_TYPE_STATS:
184 0 : return "Stats";
185 0 : case VIF_TYPE_VIRTUAL_VLAN:
186 0 : return "Virtual(Vlan)";
187 0 : case VIF_TYPE_MONITORING:
188 0 : return "Monitoring";
189 0 : default:
190 0 : return "Invalid";
191 : }
192 :
193 : return NULL;
194 : }
195 :
196 : static unsigned int
197 0 : vr_get_if_type(char *type_str)
198 : {
199 0 : if (!strncmp(type_str, VHOST_TYPE_STRING,
200 : strlen(VHOST_TYPE_STRING)))
201 0 : return VIF_TYPE_HOST;
202 0 : else if (!strncmp(type_str, AGENT_TYPE_STRING,
203 : strlen(AGENT_TYPE_STRING)))
204 0 : return VIF_TYPE_AGENT;
205 0 : else if (!strncmp(type_str, PHYSICAL_TYPE_STRING,
206 : strlen(PHYSICAL_TYPE_STRING)))
207 0 : return VIF_TYPE_PHYSICAL;
208 0 : else if (!strncmp(type_str, VIRTUAL_VLAN_TYPE_STRING,
209 : strlen(VIRTUAL_VLAN_TYPE_STRING)))
210 0 : return VIF_TYPE_VIRTUAL_VLAN;
211 0 : else if (!strncmp(type_str, VIRTUAL_TYPE_STRING,
212 : strlen(VIRTUAL_TYPE_STRING)))
213 0 : return VIF_TYPE_VIRTUAL;
214 0 : else if (!strncmp(type_str, XEN_LL_TYPE_STRING,
215 : strlen(XEN_LL_TYPE_STRING)))
216 0 : return VIF_TYPE_XEN_LL_HOST;
217 0 : else if (!strncmp(type_str, GATEWAY_TYPE_STRING,
218 : strlen(GATEWAY_TYPE_STRING)))
219 0 : return VIF_TYPE_GATEWAY;
220 0 : else if (!strncmp(type_str, STATS_TYPE_STRING,
221 : strlen(STATS_TYPE_STRING)))
222 0 : return VIF_TYPE_STATS;
223 0 : else if (!strncmp(type_str, MONITORING_TYPE_STRING,
224 : strlen(MONITORING_TYPE_STRING)))
225 0 : return VIF_TYPE_MONITORING;
226 : else
227 0 : Usage();
228 :
229 0 : return 0;
230 : }
231 :
232 : static unsigned int
233 0 : vr_get_if_transport(char *transport_str)
234 : {
235 0 : if (!strncmp(transport_str, ETH_TRANSPORT_STRING,
236 : strlen(ETH_TRANSPORT_STRING)))
237 0 : return VIF_TRANSPORT_ETH;
238 0 : else if (!strncmp(transport_str, PMD_TRASPORT_STRING,
239 : strlen(PMD_TRASPORT_STRING)))
240 0 : return VIF_TRANSPORT_PMD;
241 0 : else if (!strncmp(transport_str, VIRTUAL_TRANSPORT_STRING,
242 : strlen(VIRTUAL_TRANSPORT_STRING)))
243 0 : return VIF_TRANSPORT_VIRTUAL;
244 0 : else if (!strncmp(transport_str, SOCKET_TRANSPORT_STRING,
245 : strlen(SOCKET_TRANSPORT_STRING)))
246 0 : return VIF_TRANSPORT_SOCKET;
247 : else
248 0 : Usage();
249 :
250 0 : return 0;
251 : }
252 :
253 : static char *
254 3 : vr_if_flags(int flags)
255 : {
256 : unsigned int i, array_size;
257 3 : unsigned int all_len = 0;
258 3 : memset(flag_string, 0, sizeof(flag_string));
259 :
260 3 : array_size = sizeof(flag_metadata) / sizeof(flag_metadata[0]);
261 84 : for (i = 0; i < array_size; i++) {
262 81 : if (flags & flag_metadata[i].vuf_flag) {
263 : unsigned int flag_len;
264 8 : flag_len = strlen(flag_metadata[i].vuf_flag_symbol);
265 8 : if (all_len + flag_len < sizeof(flag_string)) {
266 8 : strcat(flag_string, flag_metadata[i].vuf_flag_symbol);
267 8 : all_len += flag_len;
268 : }
269 : else
270 0 : break;
271 : }
272 : }
273 :
274 3 : return flag_string;
275 : }
276 :
277 : static void
278 3 : vr_interface_print_header(void)
279 : {
280 : unsigned int i, array_size;
281 :
282 3 : array_size = sizeof(flag_metadata) / sizeof(flag_metadata[0]);
283 :
284 3 : printf("Vrouter Interface Table\n\n");
285 :
286 3 : printf("Flags: ");
287 :
288 84 : for (i = 0; i < array_size; i++) {
289 81 : if (i) {
290 78 : if (!(i % 4))
291 18 : printf("\n ");
292 : else
293 60 : printf(", ");
294 : }
295 81 : printf("%s=%s", flag_metadata[i].vuf_flag_symbol,
296 : flag_metadata[i].vuf_flag_string);
297 : }
298 :
299 3 : printf("\n\n");
300 3 : return;
301 : }
302 :
303 : static void
304 0 : drop_stats_req_process(void *s_req)
305 : {
306 0 : vr_drop_stats_req *stats = (vr_drop_stats_req *)s_req;
307 0 : vr_print_drop_stats(stats, core);
308 :
309 0 : return;
310 : }
311 :
312 : static void
313 0 : vrf_assign_req_process(void *s)
314 : {
315 0 : vr_vrf_assign_req *req = (vr_vrf_assign_req *)s;
316 :
317 0 : printf("%d:%d, ", req->var_vlan_id, req->var_vif_vrf);
318 0 : var_marker = req->var_vlan_id;
319 :
320 0 : return;
321 : }
322 :
323 : static int
324 21 : vr_interface_print_head_space(void)
325 : {
326 : int i;
327 :
328 273 : for (i = 0; i < 12; i++)
329 252 : printf(" ");
330 21 : return i;
331 : }
332 :
333 : char *
334 3 : vr_if_transport_string(vr_interface_req *req)
335 : {
336 3 : switch (req->vifr_transport) {
337 0 : case VIF_TRANSPORT_VIRTUAL:
338 0 : return "Virtual";
339 : break;
340 :
341 0 : case VIF_TRANSPORT_ETH:
342 0 : return "Ethernet";
343 : break;
344 :
345 3 : case VIF_TRANSPORT_PMD:
346 3 : return "PMD";
347 : break;
348 :
349 0 : case VIF_TRANSPORT_SOCKET:
350 0 : return "Socket";
351 : break;
352 :
353 0 : default:
354 0 : break;
355 : }
356 :
357 0 : return "Unknown";
358 : }
359 :
360 : static void
361 9 : vr_interface_core_print(void)
362 : {
363 9 : if (core != (unsigned)-1) {
364 0 : printf("Core %u ", core);
365 : }
366 9 : }
367 :
368 : static void
369 9 : vr_interface_nombufs_print(uint64_t nombufs)
370 : {
371 9 : if (nombufs)
372 0 : printf(" no mbufs:%" PRId64, nombufs);
373 9 : printf("\n");
374 9 : }
375 :
376 : static void
377 12 : vr_interface_pbem_counters_print(const char *title, bool print_always,
378 : uint64_t packets, uint64_t bytes, uint64_t errors,
379 : uint64_t nombufs)
380 : {
381 12 : if (print_always || packets || bytes || errors) {
382 6 : vr_interface_print_head_space();
383 6 : vr_interface_core_print();
384 6 : printf("%s packets:%" PRId64 " bytes:%" PRId64 " errors:%" PRId64,
385 : title, packets, bytes, errors);
386 6 : vr_interface_nombufs_print(nombufs);
387 : }
388 12 : }
389 :
390 : static void
391 6 : vr_interface_pesm_counters_print(const char *title, bool print_always,
392 : uint64_t packets, uint64_t errors, uint64_t syscalls,
393 : uint64_t nombufs)
394 : {
395 6 : if (print_always || packets || errors) {
396 3 : vr_interface_print_head_space();
397 3 : vr_interface_core_print();
398 3 : printf("%s packets:%" PRId64 " errors:%" PRId64,
399 : title, packets, errors);
400 3 : if (syscalls)
401 0 : printf(" syscalls:%" PRId64, syscalls);
402 3 : vr_interface_nombufs_print(nombufs);
403 : }
404 6 : }
405 :
406 : static void
407 6 : vr_interface_pe_counters_print(const char *title, bool print_always,
408 : uint64_t packets, uint64_t errors)
409 : {
410 6 : if (print_always || packets || errors) {
411 0 : vr_interface_print_head_space();
412 0 : vr_interface_core_print();
413 0 : printf("%s packets:%" PRId64 " errors:%" PRId64 "\n",
414 : title, packets, errors);
415 : }
416 6 : }
417 :
418 : static void
419 3 : vr_interface_e_per_lcore_counters_print(const char *title, bool print_always,
420 : uint64_t *errors, uint32_t size)
421 : {
422 : unsigned int i;
423 :
424 3 : vr_interface_print_head_space();
425 3 : printf("%s errors to lcore", title);
426 39 : for (i = 0; i < size; i++) {
427 36 : printf(" %" PRId64 , errors[i]);
428 : }
429 3 : printf("\n");
430 3 : }
431 :
432 : /* Display Fabric(Master) & bond Slave information only on DPDK platforms */
433 : static void
434 0 : vr_interface_fabric_info(vr_interface_req *req)
435 : {
436 :
437 : int i;
438 : char *p_name, *p_drv_name ;
439 0 : const char *fabric_link[] = {"DOWN", "UP"};
440 :
441 0 : if(req->vifr_type != VIF_TYPE_PHYSICAL)
442 0 : return;
443 :
444 0 : vr_interface_print_head_space();
445 0 : printf("Fabric Interface: %s Status: %s Driver: %s\n",
446 0 : req->vifr_fab_name, fabric_link[(req->vifr_intf_status &
447 : 0x01)], req->vifr_fab_drv_name);
448 :
449 0 : p_name = req->vifr_bond_slave_name;
450 0 : p_drv_name = req->vifr_bond_slave_drv_name;
451 :
452 0 : for(i = 0; i < req->vifr_num_bond_slave; i++) {
453 0 : vr_interface_print_head_space();
454 0 : printf("Slave Interface(%d): %s Status: %s Driver: %s\n",
455 0 : i, p_name, fabric_link[(req->vifr_intf_status >>
456 0 : (i + 1)) & 0x01], p_drv_name);
457 :
458 0 : p_name = strchr(p_name, '\0'); p_name++;
459 0 : p_drv_name = strchr(p_drv_name, '\0'); p_drv_name++;
460 : }
461 : }
462 :
463 : /* Display VLAN ID & VLAN fwd interface only on DPDK platforms */
464 : static void
465 0 : vr_interface_vlan_info(vr_interface_req *req)
466 : {
467 0 : if(req->vifr_type != VIF_TYPE_PHYSICAL)
468 0 : return;
469 :
470 0 : if(req->vifr_vlan_tag != VLAN_ID_INVALID && req->vifr_vlan_name != NULL ) {
471 0 : vr_interface_print_head_space();
472 0 : printf("Vlan Id: %d",req->vifr_vlan_tag);
473 0 : if(strlen(req->vifr_vlan_name))
474 0 : printf(" VLAN fwd Interface: %s",req->vifr_vlan_name);
475 0 : printf("\n");
476 : }
477 : }
478 :
479 : static void
480 3 : list_get_print(vr_interface_req *req)
481 : {
482 : char ip6_addr[INET6_ADDRSTRLEN], ip_addr[INET_ADDRSTRLEN],
483 3 : name[50] = {0}, ip6_ip[16];
484 3 : bool print_zero = false;
485 : uint16_t proto, port, port_data;
486 3 : int printed = 0, len;
487 : unsigned int i;
488 : uint64_t *tmp;
489 : uint8_t aggr_data;
490 : uint32_t *ip;
491 :
492 3 : if (rate_set) {
493 0 : print_zero = true;
494 : }
495 :
496 3 : printed = printf("vif%d/%d", req->vifr_rid, req->vifr_idx);
497 12 : for (; printed < 12; printed++)
498 9 : printf(" ");
499 :
500 3 : if (req->vifr_flags & VIF_FLAG_PMD) {
501 0 : printf("PMD: %d", req->vifr_os_idx);
502 3 : } else if (platform == DPDK_PLATFORM || platform == VTEST_PLATFORM) {
503 3 : switch (req->vifr_type) {
504 0 : case VIF_TYPE_PHYSICAL:
505 0 : if(req->vifr_flags & VIF_FLAG_MOCK_DEVICE)
506 0 : printf("PCI: Mock");
507 : else
508 0 : printf("PCI: ""%.4" PRIx16 ":%.2" PRIx8 ":%.2" PRIx8 ".%" PRIx8,
509 0 : (uint16_t)(req->vifr_os_idx >> 16),
510 0 : (uint8_t)(req->vifr_os_idx >> 8) & 0xFF,
511 0 : (uint8_t)(req->vifr_os_idx >> 3) & 0x1F,
512 0 : (uint8_t)(req->vifr_os_idx & 0x7));
513 0 : break;
514 :
515 0 : case VIF_TYPE_MONITORING:
516 0 : printf("Monitoring: %s for vif%d/%d", req->vifr_name,
517 : req->vifr_rid, req->vifr_os_idx);
518 0 : break;
519 :
520 3 : default:
521 3 : if (req->vifr_name)
522 3 : printf("%s: %s", vr_if_transport_string(req),
523 : req->vifr_name);
524 3 : if (req->vifr_flags & VIF_FLAG_MOCK_DEVICE)
525 3 : printf(" Mock");
526 3 : break;
527 : }
528 :
529 : } else {
530 0 : if (req->vifr_os_idx > 0) {
531 0 : printf("OS: %s", if_indextoname(req->vifr_os_idx, name));
532 : } else {
533 0 : printf(" %s", req->vifr_name);
534 : }
535 : }
536 :
537 3 : if ((req->vifr_type == VIF_TYPE_PHYSICAL) &&
538 0 : (!(req->vifr_flags & VIF_FLAG_MOCK_DEVICE))) {
539 0 : if (req->vifr_speed >= 0) {
540 0 : printf(" (Speed %d,", req->vifr_speed);
541 0 : if (req->vifr_duplex >= 0)
542 0 : printf(" Duplex %d", req->vifr_duplex);
543 0 : printf(")");
544 : }
545 3 : } else if (req->vifr_type == VIF_TYPE_VIRTUAL_VLAN) {
546 0 : printf(" Vlan(o/i)(,S): %d/%d", req->vifr_ovlan_id, req->vifr_vlan_id);
547 0 : if (req->vifr_src_mac_size && req->vifr_src_mac) {
548 0 : for (i = 0; i < (req->vifr_src_mac_size / VR_ETHER_ALEN); i = i + 1) {
549 0 : printf(", "MAC_FORMAT, MAC_VALUE((uint8_t *)
550 : (req->vifr_src_mac + (i * VR_ETHER_ALEN))));
551 0 : printf(" Bridge Index: %d", req->vifr_bridge_idx[i]);
552 : }
553 : }
554 : }
555 :
556 3 : if (req->vifr_parent_vif_idx >= 0)
557 0 : printf(" Parent:vif0/%d", req->vifr_parent_vif_idx);
558 :
559 3 : if (req->vifr_nh_id != 0)
560 0 : printf(" NH: %d", req->vifr_nh_id);
561 :
562 3 : printf("\n");
563 :
564 3 : vr_interface_print_head_space();
565 3 : printf("Type:%s HWaddr:"MAC_FORMAT" IPaddr:%s\n",
566 : vr_get_if_type_string(req->vifr_type),
567 3 : MAC_VALUE((uint8_t *)req->vifr_mac), inet_ntop(AF_INET,
568 3 : &req->vifr_ip, ip_addr, INET_ADDRSTRLEN));
569 3 : if (req->vifr_ip6_u || req->vifr_ip6_l) {
570 0 : tmp = (uint64_t *)ip6_ip;
571 0 : *tmp = req->vifr_ip6_u;
572 0 : *(tmp + 1) = req->vifr_ip6_l;
573 0 : vr_interface_print_head_space();
574 0 : printf("IP6addr:%s\n", inet_ntop(AF_INET6, ip6_ip, ip6_addr,
575 : INET6_ADDRSTRLEN));
576 : }
577 3 : vr_interface_print_head_space();
578 3 : printf("Vrf:%d Mcast Vrf:%d Flags:%s QOS:%d Ref:%d", req->vifr_vrf,
579 3 : req->vifr_mcast_vrf, req->vifr_flags ?
580 3 : vr_if_flags(req->vifr_flags) : "NULL" ,
581 3 : req->vifr_qos_map_index, req->vifr_ref_cnt);
582 3 : if (req->vifr_flags & (VIF_FLAG_MIRROR_TX | VIF_FLAG_MIRROR_RX)) {
583 0 : printf(" Mirror index %d\n", req->vifr_mir_id);
584 : } else {
585 3 : printf("\n");
586 : }
587 :
588 3 : if (platform == DPDK_PLATFORM || platform == VTEST_PLATFORM) {
589 3 : vr_interface_pbem_counters_print("RX device", print_zero,
590 3 : req->vifr_dev_ipackets, req->vifr_dev_ibytes,
591 3 : req->vifr_dev_ierrors, req->vifr_dev_inombufs);
592 3 : vr_interface_pesm_counters_print("RX port ", print_zero,
593 3 : req->vifr_port_ipackets, req->vifr_port_ierrors,
594 3 : req->vifr_port_isyscalls, req->vifr_port_inombufs);
595 3 : vr_interface_pe_counters_print("RX queue ", print_zero,
596 3 : req->vifr_queue_ipackets, req->vifr_queue_ierrors);
597 :
598 3 : vr_interface_e_per_lcore_counters_print("RX queue", print_zero,
599 3 : req->vifr_queue_ierrors_to_lcore,
600 : req->vifr_queue_ierrors_to_lcore_size);
601 : /* Bond Master(Fabric)/slave, VLAN info not valid on vtest platforms */
602 3 : if(platform != VTEST_PLATFORM) {
603 0 : vr_interface_fabric_info(req);
604 0 : vr_interface_vlan_info(req);
605 : }
606 : }
607 :
608 3 : vr_interface_pbem_counters_print("RX", true, req->vifr_ipackets,
609 3 : req->vifr_ibytes, req->vifr_ierrors, 0);
610 3 : vr_interface_pbem_counters_print("TX", true, req->vifr_opackets,
611 3 : req->vifr_obytes, req->vifr_oerrors, 0);
612 3 : if (req->vifr_isid || req->vifr_pbb_mac_size) {
613 0 : vr_interface_print_head_space();
614 0 : printf("ISID: %d Bmac: "MAC_FORMAT"\n",
615 0 : req->vifr_isid, MAC_VALUE((uint8_t *)req->vifr_pbb_mac));
616 : }
617 3 : vr_interface_print_head_space();
618 3 : printf("Drops:%" PRIu64 "\n", req->vifr_dpackets);
619 :
620 :
621 3 : if (req->vifr_in_mirror_md_size) {
622 0 : printed = vr_interface_print_head_space();
623 0 : len = printf("Ingress Mirror Metadata: ");
624 0 : printed += len;
625 0 : for (i = 0; i < req->vifr_in_mirror_md_size; i++) {
626 0 : printed += printf("%x ", 0xFF & req->vifr_in_mirror_md[i]);
627 0 : if (printed > 68) {
628 0 : printf("\n");
629 0 : printed = vr_interface_print_head_space();
630 0 : printf("%*c", len, ' ');
631 0 : printed += len;
632 : }
633 : }
634 0 : printf("\n");
635 : }
636 :
637 3 : if (req->vifr_out_mirror_md_size) {
638 0 : printed = vr_interface_print_head_space();
639 0 : len = printf("Egress Mirror Metadata: ");
640 0 : printed += len;
641 0 : for (i = 0; i < req->vifr_out_mirror_md_size; i++) {
642 0 : printed += printf("%x ", 0xFF & req->vifr_out_mirror_md[i]);
643 0 : if (printed > 68) {
644 0 : printf("\n");
645 0 : printed = vr_interface_print_head_space();
646 0 : printf("%*c", len, ' ');
647 0 : printed += len;
648 : }
649 : }
650 0 : printf("\n");
651 :
652 : }
653 :
654 3 : if (platform == DPDK_PLATFORM || platform == VTEST_PLATFORM) {
655 3 : vr_interface_pe_counters_print("TX queue ", print_zero,
656 3 : req->vifr_queue_opackets, req->vifr_queue_oerrors);
657 3 : vr_interface_pesm_counters_print("TX port ", print_zero,
658 3 : req->vifr_port_opackets, req->vifr_port_oerrors,
659 3 : req->vifr_port_osyscalls, 0);
660 3 : vr_interface_pbem_counters_print("TX device", print_zero,
661 3 : req->vifr_dev_opackets, req->vifr_dev_obytes,
662 3 : req->vifr_dev_oerrors, 0);
663 : }
664 :
665 3 : if (req->vifr_fat_flow_protocol_port_size) {
666 0 : printf("\n");
667 0 : vr_interface_print_head_space();
668 0 : printf("FatFlow rules: \n");
669 0 : for (i = 0; i < req->vifr_fat_flow_protocol_port_size; i++) {
670 0 : proto = VIF_FAT_FLOW_PROTOCOL(req->vifr_fat_flow_protocol_port[i]);
671 0 : port = VIF_FAT_FLOW_PORT(req->vifr_fat_flow_protocol_port[i]);
672 0 : port_data = VIF_FAT_FLOW_PORT_DATA(req->vifr_fat_flow_protocol_port[i]);
673 0 : aggr_data = VIF_FAT_FLOW_PREFIX_AGGR_DATA(req->vifr_fat_flow_protocol_port[i]);
674 0 : if (!proto) {
675 0 : proto = port;
676 0 : port = 0;
677 : }
678 :
679 0 : vr_interface_print_head_space();
680 0 : printf("\t");
681 0 : printf("%d:", proto);
682 0 : if (port) {
683 0 : printf("%d ", port);
684 : } else {
685 0 : printf("%c", '*');
686 : }
687 0 : if (port_data == VIF_FAT_FLOW_PORT_SIP_IGNORE)
688 0 : printf(" - Sip");
689 0 : if (port_data == VIF_FAT_FLOW_PORT_DIP_IGNORE)
690 0 : printf(" - Dip");
691 :
692 0 : switch (aggr_data) {
693 0 : case VR_AGGREGATE_SRC_IPV4:
694 0 : ip = (uint32_t *) &req->vifr_fat_flow_src_prefix_l[i];
695 0 : printf(" AggrSrc %s/%d %d",
696 : inet_ntop(AF_INET, ip, ip_addr, INET_ADDRSTRLEN),
697 0 : req->vifr_fat_flow_src_prefix_mask[i],
698 0 : req->vifr_fat_flow_src_aggregate_plen[i]);
699 0 : break;
700 0 : case VR_AGGREGATE_DST_IPV4:
701 0 : ip = (uint32_t *) &req->vifr_fat_flow_dst_prefix_l[i];
702 0 : printf(" AggrDst %s/%d %d",
703 : inet_ntop(AF_INET, ip, ip_addr, INET_ADDRSTRLEN),
704 0 : req->vifr_fat_flow_dst_prefix_mask[i],
705 0 : req->vifr_fat_flow_dst_aggregate_plen[i]);
706 0 : break;
707 0 : case VR_AGGREGATE_SRC_DST_IPV4:
708 0 : ip = (uint32_t *) &req->vifr_fat_flow_src_prefix_l[i];
709 0 : printf(" AggrSrc %s/%d %d",
710 : inet_ntop(AF_INET, ip, ip_addr, INET_ADDRSTRLEN),
711 0 : req->vifr_fat_flow_src_prefix_mask[i],
712 0 : req->vifr_fat_flow_src_aggregate_plen[i]);
713 0 : ip = (uint32_t *) &req->vifr_fat_flow_dst_prefix_l[i];
714 0 : printf(" AggrDst %s/%d %d",
715 : inet_ntop(AF_INET, ip, ip_addr, INET_ADDRSTRLEN),
716 0 : req->vifr_fat_flow_dst_prefix_mask[i],
717 0 : req->vifr_fat_flow_dst_aggregate_plen[i]);
718 0 : break;
719 0 : case VR_AGGREGATE_SRC_IPV6:
720 0 : tmp = (uint64_t *)ip6_ip;
721 0 : *tmp = req->vifr_fat_flow_src_prefix_h[i];
722 0 : *(tmp + 1) = req->vifr_fat_flow_src_prefix_l[i];
723 0 : printf(" AggrSrc %s/%d %d",
724 : inet_ntop(AF_INET6, ip6_ip, ip6_addr, INET6_ADDRSTRLEN),
725 0 : req->vifr_fat_flow_src_prefix_mask[i],
726 0 : req->vifr_fat_flow_src_aggregate_plen[i]);
727 0 : break;
728 0 : case VR_AGGREGATE_DST_IPV6:
729 0 : tmp = (uint64_t *)ip6_ip;
730 0 : *tmp = req->vifr_fat_flow_dst_prefix_h[i];
731 0 : *(tmp + 1) = req->vifr_fat_flow_dst_prefix_l[i];
732 0 : printf(" AggrDst %s/%d %d",
733 : inet_ntop(AF_INET6, ip6_ip, ip6_addr, INET6_ADDRSTRLEN),
734 0 : req->vifr_fat_flow_dst_prefix_mask[i],
735 0 : req->vifr_fat_flow_dst_aggregate_plen[i]);
736 0 : break;
737 0 : case VR_AGGREGATE_SRC_DST_IPV6:
738 0 : tmp = (uint64_t *)ip6_ip;
739 0 : *tmp = req->vifr_fat_flow_src_prefix_h[i];
740 0 : *(tmp + 1) = req->vifr_fat_flow_src_prefix_l[i];
741 0 : printf(" AggrSrc %s/%d %d",
742 : inet_ntop(AF_INET6, ip6_ip, ip6_addr, INET6_ADDRSTRLEN),
743 0 : req->vifr_fat_flow_src_prefix_mask[i],
744 0 : req->vifr_fat_flow_src_aggregate_plen[i]);
745 0 : tmp = (uint64_t *)ip6_ip;
746 0 : *tmp = req->vifr_fat_flow_dst_prefix_h[i];
747 0 : *(tmp + 1) = req->vifr_fat_flow_dst_prefix_l[i];
748 0 : printf(" AggrDst %s/%d %d",
749 : inet_ntop(AF_INET6, ip6_ip, ip6_addr, INET6_ADDRSTRLEN),
750 0 : req->vifr_fat_flow_dst_prefix_mask[i],
751 0 : req->vifr_fat_flow_dst_aggregate_plen[i]);
752 0 : break;
753 0 : default:
754 0 : break;
755 : }
756 :
757 0 : printf("\n");
758 : }
759 : }
760 3 : printf("\n");
761 3 : if (req->vifr_fat_flow_exclude_ip_list_size) {
762 0 : vr_interface_print_head_space();
763 0 : printf("FatFlows IPv4 exclude prefix list:\n");
764 0 : for (i = 0; i < req->vifr_fat_flow_exclude_ip_list_size; i++) {
765 0 : vr_interface_print_head_space();
766 0 : printf("\t%s\n", inet_ntop(AF_INET, &req->vifr_fat_flow_exclude_ip_list[i], ip_addr, INET_ADDRSTRLEN));
767 : }
768 0 : printf("\n");
769 : }
770 3 : if (req->vifr_fat_flow_exclude_ip6_u_list_size) {
771 0 : vr_interface_print_head_space();
772 0 : printf("FatFlows IPv6 exclude prefix list:\n");
773 0 : for (i = 0; i < req->vifr_fat_flow_exclude_ip6_u_list_size; i++) {
774 0 : tmp = (uint64_t *)ip6_ip;
775 0 : *tmp = req->vifr_fat_flow_exclude_ip6_u_list[i];
776 0 : *(tmp + 1) = req->vifr_fat_flow_exclude_ip6_l_list[i];
777 0 : vr_interface_print_head_space();
778 0 : printf("\t%s\n", inet_ntop(AF_INET6, ip6_ip, ip6_addr, INET6_ADDRSTRLEN));
779 : }
780 0 : printf("\n");
781 : }
782 :
783 3 : if (get_set && req->vifr_flags & VIF_FLAG_SERVICE_IF) {
784 0 : vr_vrf_assign_dump = true;
785 0 : dump_pending = true;
786 0 : printf("VRF table(vlan:vrf):\n");
787 0 : vr_ifindex = req->vifr_idx;
788 : }
789 :
790 3 : return;
791 : }
792 :
793 : static void
794 0 : list_header_print(void)
795 : {
796 0 : int printed = 0;
797 :
798 0 : printed = printf("Interface name");
799 0 : for (; printed < 30; printed++)
800 0 : printf(" ");
801 :
802 0 : printed = printf("VIF ID");
803 0 : for (; printed < 30; printed++)
804 0 : printf(" ");
805 :
806 0 : printed = printf("RX");
807 0 : for (; printed < 30; printed++)
808 0 : printf(" ");
809 :
810 0 : printed = printf("TX");
811 0 : for (; printed < 30; printed++)
812 0 : printf(" ");
813 :
814 0 : printf("\n");
815 :
816 0 : printed = strlen("Errors");
817 0 : for (; printed < 30 * 2; printed++)
818 0 : printf(" ");
819 :
820 0 : printed = printf("Errors Packets");
821 0 : for (; printed < 30; printed++)
822 0 : printf(" ");
823 :
824 0 : printf("Errors Packets");
825 :
826 0 : printf("\n\n");
827 0 : }
828 :
829 : static void
830 0 : list_rate_print(vr_interface_req *req)
831 : {
832 0 : int printed = 0;
833 0 : uint64_t tx_errors = 0;
834 0 : uint64_t rx_errors = 0;
835 0 : unsigned int i = 0;
836 :
837 0 : rx_errors = (req->vifr_dev_ierrors + req->vifr_port_ierrors + req->vifr_queue_ierrors
838 0 : + req->vifr_ierrors);
839 0 : tx_errors = (req->vifr_dev_oerrors + req->vifr_port_oerrors + req->vifr_queue_oerrors
840 0 : + req->vifr_oerrors);
841 :
842 0 : printed = printf("%s: %s", vr_get_if_type_string(req->vifr_type),
843 : req->vifr_name);
844 0 : for (; printed < 30; printed++)
845 0 : printf(" ");
846 0 : printed = printf("vif%d/%d", req->vifr_rid, req->vifr_idx);
847 0 : for (; printed < 24; printed++)
848 0 : printf(" ");
849 :
850 0 : printed = printf("%-7"PRIu64 " %-7"PRIu64, rx_errors, req->vifr_ipackets);
851 0 : for (; printed < 30; printed++)
852 0 : printf(" ");
853 :
854 0 : printed = printf("%-7"PRIu64 " %-7"PRIu64, tx_errors, req->vifr_opackets);
855 0 : for (; printed < 25; printed++)
856 0 : printf(" ");
857 0 : printf("\n\n\n");
858 0 : return;
859 : }
860 :
861 : static void
862 0 : rate_process(vr_interface_req *req, vr_interface_req *prev_req)
863 : {
864 0 : vr_interface_req rate_req_temp = {0};
865 0 : uint64_t *temp_prev_req_ptr = NULL;
866 :
867 0 : if (first_rate_iter) {
868 0 : temp_prev_req_ptr = prev_req->vifr_queue_ierrors_to_lcore;
869 0 : *prev_req = *req;
870 0 : prev_req->vifr_queue_ierrors_to_lcore = temp_prev_req_ptr;
871 0 : if (!prev_req->vifr_queue_ierrors_to_lcore) {
872 0 : prev_req->vifr_queue_ierrors_to_lcore =
873 0 : malloc(req->vifr_queue_ierrors_to_lcore_size * sizeof(uint64_t));
874 0 : if (!prev_req->vifr_queue_ierrors_to_lcore)
875 0 : return;
876 : }
877 :
878 0 : memcpy(prev_req->vifr_queue_ierrors_to_lcore,
879 0 : req->vifr_queue_ierrors_to_lcore,
880 0 : req->vifr_queue_ierrors_to_lcore_size * sizeof(uint64_t));
881 0 : rate_stats_diff(req, prev_req);
882 0 : return;
883 : }
884 :
885 0 : rate_req_temp = *req;
886 0 : rate_req_temp.vifr_queue_ierrors_to_lcore =
887 0 : calloc(req->vifr_queue_ierrors_to_lcore_size, sizeof(uint64_t));
888 :
889 0 : if (!rate_req_temp.vifr_queue_ierrors_to_lcore) {
890 0 : fprintf(stderr, "Fail, memory allocation. (%s:%d).", __FILE__ , __LINE__);
891 0 : exit(1);
892 : }
893 :
894 0 : memcpy(rate_req_temp.vifr_queue_ierrors_to_lcore,
895 0 : req->vifr_queue_ierrors_to_lcore,
896 0 : req->vifr_queue_ierrors_to_lcore_size * sizeof(uint64_t));
897 :
898 0 : rate_stats_diff(req, prev_req);
899 :
900 0 : temp_prev_req_ptr = prev_req->vifr_queue_ierrors_to_lcore;
901 0 : *prev_req = rate_req_temp;
902 0 : prev_req->vifr_queue_ierrors_to_lcore = temp_prev_req_ptr;
903 :
904 0 : memcpy(prev_req->vifr_queue_ierrors_to_lcore,
905 0 : rate_req_temp.vifr_queue_ierrors_to_lcore,
906 0 : rate_req_temp.vifr_queue_ierrors_to_lcore_size * sizeof(uint64_t));
907 :
908 0 : if ((rate_req_temp.vifr_queue_ierrors_to_lcore)) {
909 0 : free(rate_req_temp.vifr_queue_ierrors_to_lcore);
910 0 : rate_req_temp.vifr_queue_ierrors_to_lcore = NULL;
911 : }
912 : }
913 :
914 : /*
915 : * The function is called by functions sandesh_decode.
916 : * In case, when we have sent SANDESH_OP_DUMP (usually --list parameter) msg to nl_client,
917 : * then sandesh_decode calls vr_interface_req_process in "loop".
918 : * Variable dump_marker (dump_marker < next_interface.vif_id) sets which
919 : * interface is successor.
920 : *
921 : * For SANDESH_OP_DUMP msg we SHOULD change variable dump_marker;
922 : * Otherwise we can be in infinity loop.
923 : */
924 : static void
925 4 : interface_req_process(void *s)
926 : {
927 4 : vr_interface_req *req = (vr_interface_req *)s;
928 :
929 4 : if(req->h_op == SANDESH_OP_RESET) {
930 1 : if(req->vifr_idx == -1) {
931 1 : if(req->vifr_core != 0) {
932 0 : printf("\nVif stats cleared successfully on core %d for all interfacess \n\n",
933 0 : req->vifr_core-1);
934 : } else {
935 1 : printf("\nVif stats cleared successfully on all cores for all interfaces \n\n");
936 : }
937 : } else {
938 0 : if(req->vifr_core != 0) {
939 0 : printf("\nVif stats cleared successfully for %s on core %d \n\n",
940 0 : req->vifr_name, req->vifr_core-1);
941 : } else {
942 0 : printf("\nVif stats cleared successfully for %s on all cores \n\n",
943 : req->vifr_name);
944 : }
945 : }
946 1 : return;
947 : }
948 :
949 3 : if (add_set)
950 0 : vr_ifindex = req->vifr_idx;
951 :
952 3 : if (!get_set && !list_set)
953 0 : return;
954 :
955 3 : if (rate_set) {
956 : /* Compute for each "current" vif interfaces. */
957 0 : rate_process(req, &prev_req[req->vifr_idx % VR_MAX_INTERFACES]);
958 :
959 0 : if (list_set) {
960 : /*
961 : * We are in loop (which cannot be controlled by us)
962 : * (see function comment)
963 : *
964 : * Ignores first interfaces outputs.
965 : */
966 0 : if (ignore_number_interface > 0) {
967 0 : ignore_number_interface--;
968 : /*
969 : * How many interface we should print
970 : * Value of variable number_interface is computed:
971 : * (get_terminal_lines - header_lines)/(lines_per_interface)
972 : */
973 0 : } else if (print_number_interface >= 1) {
974 0 : list_rate_print(req);
975 0 : print_number_interface--;
976 : }
977 : /* Mandatory, otherwise we can be in infinity loop.*/
978 0 : dump_marker = req->vifr_idx;
979 0 : return;
980 : }
981 : }
982 3 : list_get_print(req);
983 3 : if (list_set){
984 :
985 0 : dump_marker = req->vifr_idx;
986 : }
987 :
988 3 : return;
989 : }
990 :
991 : static void
992 12 : response_process(void *s)
993 : {
994 12 : vr_response_common_process((vr_response *)s, &dump_pending);
995 12 : return;
996 : }
997 :
998 : static void
999 12 : vif_fill_nl_callbacks()
1000 : {
1001 12 : nl_cb.vr_drop_stats_req_process = drop_stats_req_process;
1002 12 : nl_cb.vr_vrf_assign_req_process = vrf_assign_req_process;
1003 12 : nl_cb.vr_interface_req_process = interface_req_process;
1004 12 : nl_cb.vr_response_process = response_process;
1005 12 : }
1006 :
1007 : /*
1008 : * create vhost interface in linux
1009 : */
1010 : static int
1011 0 : vhost_create(void)
1012 : {
1013 : int ret;
1014 : #if defined(__linux__)
1015 : struct vn_if vhost;
1016 : struct nl_response *resp;
1017 :
1018 0 : memset(&vhost, 0, sizeof(vhost));
1019 0 : strncpy(vhost.if_name, if_name, sizeof(vhost.if_name) - 1);
1020 0 : strncpy(vhost.if_kind, VHOST_KIND, sizeof(vhost.if_kind) - 1);
1021 0 : memcpy(vhost.if_mac, vr_ifmac, sizeof(vhost.if_mac));
1022 0 : ret = nl_build_if_create_msg(cl, &vhost, 0);
1023 0 : if (ret)
1024 0 : return ret;
1025 :
1026 0 : ret = nl_sendmsg(cl);
1027 0 : if (ret <= 0)
1028 0 : return ret;
1029 :
1030 0 : if ((ret = nl_recvmsg(cl)) > 0) {
1031 0 : resp = nl_parse_reply(cl);
1032 0 : if (resp && resp->nl_op)
1033 0 : printf("%s: %s\n", __func__, strerror(resp->nl_op));
1034 : }
1035 : #else
1036 : #error "Unsupported platform"
1037 : #endif
1038 0 : return ret;
1039 : }
1040 :
1041 : static int
1042 12 : vr_intf_op(struct nl_client *cl, unsigned int op)
1043 : {
1044 12 : int ret = -EINVAL, vrf;
1045 12 : bool dump = false;
1046 :
1047 12 : if (create_set)
1048 0 : return vhost_create();
1049 :
1050 12 : if ((op == SANDESH_OP_DUMP && !(rate_set)) ||
1051 3 : ((op == SANDESH_OP_GET) && !(add_set) )) {
1052 3 : vr_interface_print_header();
1053 9 : } else if (rate_set) {
1054 0 : list_header_print();
1055 : }
1056 :
1057 9 : op_retry:
1058 12 : switch (op) {
1059 0 : case SANDESH_OP_ADD:
1060 0 : if (set_set)
1061 0 : vrf = -1;
1062 : else
1063 0 : vrf = vrf_id;
1064 :
1065 0 : if (if_kindex < 0)
1066 0 : if_kindex = 0;
1067 :
1068 0 : if (vindex_set)
1069 0 : vr_ifindex = vif_index;
1070 :
1071 0 : if (vr_ifindex < 0)
1072 0 : vr_ifindex = if_kindex;
1073 :
1074 0 : ret = vr_send_interface_add(cl, 0, if_name, if_kindex, vr_ifindex,
1075 : if_xconnect_kindex, vr_if_type, vrf, vr_ifflags, vr_ifmac, vr_transport, NULL);
1076 0 : break;
1077 :
1078 8 : case SANDESH_OP_DEL:
1079 8 : ret = vr_send_interface_delete(cl, 0, if_name, vr_ifindex);
1080 8 : break;
1081 :
1082 3 : case SANDESH_OP_GET:
1083 : /**
1084 : * Implementation of getting per-core vif statistics is based on this
1085 : * little trick to avoid making changes in how agent makes requests for
1086 : * statistics. From vRouter's and agent's point of view, request for
1087 : * stats for 0th core means a request for stats summed up for all the
1088 : * cores. So cores are enumerated starting with 1.
1089 : * Meanwhile, from user's point of view they are enumerated starting
1090 : * with 0 (e.g. vif --list --core 0 means 'vif statistics for the very
1091 : * first (0th) core'). This is how Linux enumerates CPUs, so it should
1092 : * be more intuitive for the user.
1093 : *
1094 : * Agent is not aware of possibility of asking for per-core stats. Its
1095 : * requests have vifr_core implicitly set to 0. So we need to make a
1096 : * conversion between those enumerating systems. The vif utility
1097 : * increments by 1 the core number user asked for. Then it is
1098 : * decremented back in vRouter.
1099 : */
1100 3 : if (!vr_vrf_assign_dump) {
1101 3 : ret = vr_send_interface_get(cl, 0, vr_ifindex, if_kindex,
1102 3 : core + 1, drop_set);
1103 : } else {
1104 0 : dump = true;
1105 0 : ret = vr_send_vrf_assign_dump(cl, 0, vr_ifindex, var_marker);
1106 : }
1107 3 : break;
1108 :
1109 0 : case SANDESH_OP_DUMP:
1110 0 : dump = true;
1111 0 : ret = vr_send_interface_dump(cl, 0, dump_marker, core + 1);
1112 0 : break;
1113 :
1114 1 : case SANDESH_OP_RESET:
1115 1 : ret = vr_send_vif_clear_stats(cl, 0, vif_index, core);
1116 1 : break;
1117 : }
1118 :
1119 :
1120 12 : if (ret < 0)
1121 0 : return ret;
1122 :
1123 :
1124 12 : ret = vr_recvmsg(cl, dump);
1125 12 : if (ret <= 0)
1126 0 : return ret;
1127 :
1128 12 : if (set_set) {
1129 0 : ret = vr_send_vrf_assign_set(cl, 0, vr_ifindex, vlan_id, vrf_id);
1130 0 : if (ret < 0)
1131 0 : return ret;
1132 :
1133 0 : return vr_recvmsg(cl, dump);
1134 : }
1135 :
1136 12 : if (dump_pending) {
1137 0 : goto op_retry;
1138 : }
1139 :
1140 12 : return 0;
1141 : }
1142 :
1143 : static void
1144 0 : usage_internal(const char *msg)
1145 : {
1146 0 : printf("Invalid arguments for %s \n", msg);
1147 0 : exit(0);
1148 : }
1149 :
1150 : static void
1151 0 : Usage()
1152 : {
1153 0 : printf("Usage: vif [--create <intf_name> --mac <mac>]\n");
1154 0 : printf("\t [--add <intf_name> --mac <mac> --vrf <vrf>\n");
1155 0 : printf("\t \t--type [vhost|agent|physical|virtual|monitoring]\n");
1156 0 : printf("\t \t--transport [eth|pmd|virtual|socket]\n");
1157 0 : printf("\t \t--xconnect <physical interface name>\n");
1158 0 : printf("\t \t--policy, --vhost-phys, --dhcp-enable]\n");
1159 0 : printf("\t \t--vif <vif ID> --id <intf_id> --pmd --pci]\n");
1160 0 : printf("\t [--delete <intf_id>|<intf_name>]\n");
1161 0 : printf("\t [--get <intf_id>][--kernel][--core <core number>][--rate] [--get-drop-stats]\n");
1162 0 : printf("\t [--set <intf_id> --vlan <vlan_id> --vrf <vrf_id>]\n");
1163 0 : printf("\t [--list][--core <core number>][--rate]\n");
1164 0 : printf("\t [--sock-dir <sock dir>]\n");
1165 0 : printf("\t [--clear][--id <intf_id>][--core <core_number>]\n");
1166 0 : printf("\t [--help]\n");
1167 :
1168 0 : exit(0);
1169 : }
1170 :
1171 :
1172 : enum if_opt_index {
1173 : ADD_OPT_INDEX,
1174 : CREATE_OPT_INDEX,
1175 : GET_OPT_INDEX,
1176 : RATE_OPT_INDEX,
1177 : DROP_OPT_INDEX,
1178 : LIST_OPT_INDEX,
1179 : VRF_OPT_INDEX,
1180 : MAC_OPT_INDEX,
1181 : DELETE_OPT_INDEX,
1182 : POLICY_OPT_INDEX,
1183 : PMD_OPT_INDEX,
1184 : PCI_OPT_INDEX,
1185 : KINDEX_OPT_INDEX,
1186 : TYPE_OPT_INDEX,
1187 : TRANSPORT_OPT_INDEX,
1188 : SET_OPT_INDEX,
1189 : VLAN_OPT_INDEX,
1190 : XCONNECT_OPT_INDEX,
1191 : VIF_OPT_INDEX,
1192 : DHCP_OPT_INDEX,
1193 : VHOST_PHYS_OPT_INDEX,
1194 : HELP_OPT_INDEX,
1195 : VINDEX_OPT_INDEX,
1196 : CORE_OPT_INDEX,
1197 : SOCK_DIR_OPT_INDEX,
1198 : CLEAR_STATS_OPT_INDEX,
1199 : MAX_OPT_INDEX
1200 : };
1201 :
1202 : static struct option long_options[] = {
1203 : [ADD_OPT_INDEX] = {"add", required_argument, &add_set, 1},
1204 : [CREATE_OPT_INDEX] = {"create", required_argument, &create_set, 1},
1205 : [GET_OPT_INDEX] = {"get", required_argument, &get_set, 1},
1206 : [RATE_OPT_INDEX] = {"rate", no_argument, &rate_set, 1},
1207 : [DROP_OPT_INDEX] = {"get-drop-stats",no_argument, &drop_set, 1},
1208 : [LIST_OPT_INDEX] = {"list", no_argument, &list_set, 1},
1209 : [VRF_OPT_INDEX] = {"vrf", required_argument, &vrf_set, 1},
1210 : [MAC_OPT_INDEX] = {"mac", required_argument, &mac_set, 1},
1211 : [DELETE_OPT_INDEX] = {"delete", required_argument, &delete_set, 1},
1212 : [POLICY_OPT_INDEX] = {"policy", no_argument, &policy_set, 1},
1213 : [PMD_OPT_INDEX] = {"pmd", no_argument, &pmd_set, 1},
1214 : [PCI_OPT_INDEX] = {"pci", no_argument, &pci_set, 1},
1215 : [KINDEX_OPT_INDEX] = {"kernel", no_argument, &kindex_set, 1},
1216 : [TYPE_OPT_INDEX] = {"type", required_argument, &type_set, 1},
1217 : [TRANSPORT_OPT_INDEX] = {"transport", required_argument, &transport_set, 1},
1218 : [SET_OPT_INDEX] = {"set", required_argument, &set_set, 1},
1219 : [VLAN_OPT_INDEX] = {"vlan", required_argument, &vlan_set, 1},
1220 : [VHOST_PHYS_OPT_INDEX] = {"vhost-phys", no_argument, &vhost_phys_set, 1},
1221 : [XCONNECT_OPT_INDEX] = {"xconnect", required_argument, &xconnect_set, 1},
1222 : [VIF_OPT_INDEX] = {"vif", required_argument, &vif_set, 1},
1223 : [DHCP_OPT_INDEX] = {"dhcp-enable", no_argument, &dhcp_set, 1},
1224 : [HELP_OPT_INDEX] = {"help", no_argument, &help_set, 1},
1225 : [VINDEX_OPT_INDEX] = {"id", required_argument, &vindex_set, 1},
1226 : [CORE_OPT_INDEX] = {"core", required_argument, &core_set, 1},
1227 : [SOCK_DIR_OPT_INDEX] = {"sock-dir", required_argument, &sock_dir_set, 1},
1228 : [CLEAR_STATS_OPT_INDEX] = {"clear", no_argument, &clear_stats_set, 1},
1229 : [MAX_OPT_INDEX] = { NULL, 0, NULL, 0},
1230 : };
1231 :
1232 :
1233 : /* Safer than raw strtoul call that can segment fault with NULL strings.
1234 : sets errno if any addtional errors are detected.*/
1235 : static unsigned long
1236 11 : safer_strtoul(const char *nptr, char **endptr, int base)
1237 : {
1238 11 : if (nptr == NULL) {
1239 0 : errno = EINVAL;
1240 0 : return 0;
1241 : } else {
1242 11 : return strtoul(nptr, endptr, base);
1243 : }
1244 : }
1245 :
1246 : static int
1247 3 : is_number(const char *nptr)
1248 : {
1249 : unsigned int i;
1250 3 : if (nptr == NULL) {
1251 0 : errno = EINVAL;
1252 0 : return 0;
1253 : } else {
1254 15 : for (i = 0; i < strlen(nptr); i++) {
1255 12 : if (!isdigit(nptr[i])) {
1256 0 : return 0;
1257 : }
1258 : }
1259 : }
1260 3 : return 1;
1261 : }
1262 :
1263 : static void
1264 24 : parse_long_opts(int option_index, char *opt_arg)
1265 : {
1266 24 : int i = 0;
1267 : char *sep_arg;
1268 24 : errno = 0;
1269 24 : int retVal = -1;
1270 :
1271 :
1272 24 : if (!*(long_options[option_index].flag))
1273 0 : *(long_options[option_index].flag) = 1;
1274 :
1275 24 : switch (option_index) {
1276 0 : case ADD_OPT_INDEX:
1277 0 : strncpy(if_name, opt_arg, sizeof(if_name) - 1);
1278 0 : if_kindex = if_nametoindex(opt_arg);
1279 0 : if (isdigit(opt_arg[0]))
1280 0 : if_pmdindex = strtol(opt_arg, NULL, 0);
1281 0 : vr_op = SANDESH_OP_ADD;
1282 0 : break;
1283 :
1284 0 : case CREATE_OPT_INDEX:
1285 0 : strncpy(if_name, opt_arg, sizeof(if_name) - 1);
1286 0 : break;
1287 :
1288 0 : case VRF_OPT_INDEX:
1289 0 : if (is_number(opt_arg))
1290 0 : vrf_id = safer_strtoul(opt_arg, NULL, 0);
1291 : else
1292 0 : usage_internal("vif set --vrf");
1293 :
1294 0 : if (errno)
1295 0 : Usage();
1296 0 : break;
1297 :
1298 0 : case MAC_OPT_INDEX:
1299 0 : mac_opt = ether_aton(opt_arg);
1300 0 : if (mac_opt)
1301 0 : memcpy(vr_ifmac, mac_opt, sizeof(vr_ifmac));
1302 0 : break;
1303 :
1304 8 : case DELETE_OPT_INDEX:
1305 8 : vr_op = SANDESH_OP_DEL;
1306 8 : if (isdigit(opt_arg[0]))
1307 8 : vr_ifindex = safer_strtoul(opt_arg, NULL, 0);
1308 : else
1309 0 : strncpy(if_name, opt_arg, sizeof(if_name) - 1);
1310 8 : if (errno)
1311 0 : Usage();
1312 8 : break;
1313 :
1314 3 : case GET_OPT_INDEX:
1315 3 : vr_op = SANDESH_OP_GET;
1316 3 : if (is_number(opt_arg))
1317 3 : vr_ifindex = safer_strtoul(opt_arg, NULL, 0);
1318 : else
1319 0 : usage_internal("vif --get");
1320 :
1321 3 : if (errno)
1322 0 : Usage();
1323 3 : break;
1324 :
1325 0 : case VIF_OPT_INDEX:
1326 : /* we carry monitored vif index in OS index field */
1327 0 : if (is_number(opt_arg))
1328 0 : if_kindex = safer_strtoul(opt_arg, NULL, 0);
1329 : else
1330 0 : usage_internal("vif add --vif");
1331 :
1332 0 : if (errno)
1333 0 : Usage();
1334 0 : break;
1335 :
1336 0 : case VINDEX_OPT_INDEX:
1337 0 : if (is_number(opt_arg))
1338 0 : vif_index = safer_strtoul(opt_arg, NULL, 0);
1339 : else
1340 0 : usage_internal("vif add --id");
1341 :
1342 0 : if (errno)
1343 0 : Usage();
1344 0 : break;
1345 :
1346 0 : case POLICY_OPT_INDEX:
1347 0 : vr_ifflags |= VIF_FLAG_POLICY_ENABLED;
1348 0 : break;
1349 :
1350 0 : case PMD_OPT_INDEX:
1351 0 : vr_ifflags |= VIF_FLAG_PMD;
1352 0 : break;
1353 :
1354 0 : case LIST_OPT_INDEX:
1355 0 : vr_op = SANDESH_OP_DUMP;
1356 0 : break;
1357 :
1358 0 : case CORE_OPT_INDEX:
1359 0 : core = (unsigned)strtol(opt_arg, NULL, 0);
1360 0 : if (errno) {
1361 0 : printf("Error parsing core %s: %s (%d)\n", opt_arg,
1362 0 : strerror(errno), errno);
1363 0 : Usage();
1364 : }
1365 0 : break;
1366 :
1367 0 : case TYPE_OPT_INDEX:
1368 0 : vr_if_type = vr_get_if_type(optarg);
1369 0 : if (vr_if_type == VIF_TYPE_HOST)
1370 0 : need_xconnect_if = true;
1371 0 : if (vr_if_type == VIF_TYPE_MONITORING) {
1372 0 : if (platform != DPDK_PLATFORM)
1373 0 : Usage();
1374 :
1375 0 : need_vif_id = true;
1376 : /* set default values for mac and vrf */
1377 0 : vrf_id = 0;
1378 0 : vrf_set = 1;
1379 0 : vr_ifmac[0] = 0x2; /* locally administered */
1380 0 : mac_set = 1;
1381 : }
1382 0 : break;
1383 :
1384 0 : case TRANSPORT_OPT_INDEX:
1385 0 : vr_transport = vr_get_if_transport(optarg);
1386 0 : break;
1387 :
1388 0 : case SET_OPT_INDEX:
1389 0 : vr_op = SANDESH_OP_ADD;
1390 0 : if (is_number(opt_arg))
1391 0 : vr_ifindex = safer_strtoul(opt_arg, NULL, 0);
1392 : else
1393 0 : usage_internal("vif --set");
1394 :
1395 0 : if (errno)
1396 0 : Usage();
1397 0 : break;
1398 :
1399 0 : case VLAN_OPT_INDEX:
1400 0 : vr_ifflags |= VIF_FLAG_SERVICE_IF;
1401 0 : if (is_number(opt_arg))
1402 0 : vlan_id = safer_strtoul(opt_arg, NULL, 0);
1403 : else
1404 0 : usage_internal("vif set --vlan");
1405 0 : if (errno)
1406 0 : Usage();
1407 0 : break;
1408 :
1409 0 : case XCONNECT_OPT_INDEX:
1410 0 : opt_arg = strdup(opt_arg);
1411 0 : while ((sep_arg = strsep(&opt_arg, ",")) != NULL) {
1412 0 : if(platform == DPDK_PLATFORM) {
1413 : /* we need to check cross_connect index has be passed or
1414 : * not for kernel & DPDK based platforms */
1415 : /*Incase of DPDK platform, vif_idx is passed for xconnect */
1416 0 : if_xconnect_kindex[i++] = safer_strtoul(sep_arg, NULL, 0);
1417 : } else {
1418 0 : retVal = if_nametoindex(sep_arg);
1419 0 : if(0 == retVal) {
1420 0 : break;
1421 : }
1422 0 : if_xconnect_kindex[i++] = retVal;
1423 : }
1424 0 : if (isdigit(sep_arg[0])) {
1425 0 : if_pmdindex = strtol(sep_arg, NULL, 0);
1426 0 : } else if (!if_xconnect_kindex[i]) {
1427 0 : printf("%s does not seem to be a valid physical interface name\n",
1428 : sep_arg);
1429 0 : Usage();
1430 : }
1431 0 : if (if_pmdindex != -1)
1432 0 : break;
1433 : }
1434 0 : break;
1435 :
1436 0 : case DHCP_OPT_INDEX:
1437 0 : vr_ifflags |= VIF_FLAG_DHCP_ENABLED;
1438 0 : break;
1439 :
1440 0 : case VHOST_PHYS_OPT_INDEX:
1441 0 : vr_ifflags |= VIF_FLAG_VHOST_PHYS;
1442 0 : break;
1443 :
1444 12 : case SOCK_DIR_OPT_INDEX:
1445 12 : vr_socket_dir = opt_arg;
1446 12 : break;
1447 :
1448 1 : case CLEAR_STATS_OPT_INDEX:
1449 1 : clear_stats_set = 1;
1450 1 : vr_op = SANDESH_OP_RESET;
1451 1 : break;
1452 0 : default:
1453 0 : break;
1454 : }
1455 :
1456 24 : return;
1457 : }
1458 :
1459 : static void
1460 12 : validate_options(void)
1461 : {
1462 12 : unsigned int sum_opt = 0, i;
1463 :
1464 336 : for (i = 0; i < (sizeof(long_options) / sizeof(long_options[0])); i++) {
1465 324 : if (long_options[i].flag)
1466 312 : sum_opt += *(long_options[i].flag);
1467 : }
1468 :
1469 : /*
1470 : * Reduce sum_opt by 1 so that rest of the validation logic doesn't take
1471 : * sock_dir_set into account
1472 : */
1473 12 : if (sock_dir_set) {
1474 12 : sum_opt -=1;
1475 : }
1476 :
1477 12 : if (!sum_opt || help_set)
1478 0 : Usage();
1479 :
1480 12 : if (pmd_set || pci_set) {
1481 0 : if_kindex = if_pmdindex;
1482 0 : if_xconnect_kindex[0] = if_pmdindex;
1483 : }
1484 :
1485 12 : if (create_set) {
1486 0 : if ((sum_opt > 1) && (sum_opt != 2 || !mac_set))
1487 0 : Usage();
1488 0 : return;
1489 : }
1490 12 : if (get_set) {
1491 3 : if ((sum_opt > 1) && (sum_opt != 3) && (sum_opt != 4) &&
1492 0 : (!kindex_set && !core_set && !rate_set && !drop_set))
1493 0 : Usage();
1494 3 : return;
1495 : }
1496 9 : if (delete_set) {
1497 8 : if (sum_opt > 1)
1498 0 : Usage();
1499 8 : return;
1500 : }
1501 1 : if (list_set) {
1502 0 : if (drop_set)
1503 0 : Usage();
1504 0 : if (!core_set) {
1505 0 : if (rate_set && !(sum_opt > 2))
1506 0 : return;
1507 0 : if (sum_opt > 1)
1508 0 : Usage();
1509 : } else {
1510 0 : if(rate_set && !(sum_opt > 3))
1511 0 : return;
1512 0 : if (sum_opt != 2)
1513 0 : Usage();
1514 : }
1515 0 : return;
1516 : }
1517 :
1518 1 : if (add_set) {
1519 0 : if (get_set || list_set)
1520 0 : Usage();
1521 0 : if (!vrf_set || !mac_set || !type_set)
1522 0 : Usage();
1523 0 : if (need_xconnect_if && !xconnect_set)
1524 0 : Usage();
1525 0 : if (need_vif_id && !vif_set)
1526 0 : Usage();
1527 0 : return;
1528 : }
1529 :
1530 1 : if (set_set) {
1531 0 : if (sum_opt != 3 || !vrf_set || !vlan_set)
1532 0 : Usage();
1533 0 : return;
1534 : }
1535 :
1536 : /**
1537 : * Statistics per CPU core could be requested as an additional parameter
1538 : * to --list or --get.
1539 : */
1540 1 : if(core_set){
1541 0 : if (clear_stats_set)
1542 0 : return;
1543 : }
1544 1 : if (core_set) {
1545 0 : if (!list_set || !get_set)
1546 0 : Usage();
1547 : }
1548 1 : if (rate_set) {
1549 0 : if (!get_set) {
1550 0 : Usage();
1551 : }
1552 : }
1553 :
1554 1 : return;
1555 : }
1556 :
1557 :
1558 : static void
1559 0 : rate_stats_diff(vr_interface_req *req, vr_interface_req *prev_req)
1560 : {
1561 : struct timeval now;
1562 0 : int64_t diff_ms = 0;
1563 0 : unsigned int i = 0;
1564 :
1565 0 : gettimeofday(&now, NULL);
1566 0 : diff_ms = (now.tv_sec - last_time.tv_sec) * 1000;
1567 0 : diff_ms += (now.tv_usec - last_time.tv_usec) / 1000;
1568 0 : assert(diff_ms > 0);
1569 :
1570 : /* TODO:
1571 : * Sometimes error counters have decreasing trend.
1572 : *
1573 : * Workaround:
1574 : * If previous value is bigger than current value, then we assign
1575 : * previous value to current value => difference is equal to 0
1576 : */
1577 :
1578 0 : CORRECT_ERROR_CNT(&(req->vifr_dev_ierrors), &(prev_req->vifr_dev_ierrors));
1579 0 : CORRECT_ERROR_CNT(&(req->vifr_port_ierrors), &(prev_req->vifr_port_ierrors));
1580 0 : CORRECT_ERROR_CNT(&(req->vifr_queue_ierrors), &(prev_req->vifr_queue_ierrors));
1581 0 : CORRECT_ERROR_CNT(&(req->vifr_ierrors), &(prev_req->vifr_ierrors));
1582 :
1583 0 : CORRECT_ERROR_CNT(&(req->vifr_dev_oerrors), &(prev_req->vifr_dev_oerrors));
1584 0 : CORRECT_ERROR_CNT(&(req->vifr_port_oerrors), &(prev_req->vifr_port_oerrors));
1585 0 : CORRECT_ERROR_CNT(&(req->vifr_queue_oerrors), &(prev_req->vifr_queue_oerrors));
1586 0 : CORRECT_ERROR_CNT(&(req->vifr_oerrors), &(prev_req->vifr_oerrors));
1587 :
1588 : /* RX */
1589 0 : COMPUTE_DIFFERENCE(req, prev_req, vifr_dev_ibytes, diff_ms);
1590 0 : COMPUTE_DIFFERENCE(req, prev_req, vifr_dev_ipackets, diff_ms);
1591 0 : COMPUTE_DIFFERENCE(req, prev_req, vifr_dev_ierrors, diff_ms);
1592 0 : COMPUTE_DIFFERENCE(req, prev_req, vifr_dev_inombufs, diff_ms);
1593 :
1594 0 : COMPUTE_DIFFERENCE(req, prev_req, vifr_port_isyscalls, diff_ms);
1595 0 : COMPUTE_DIFFERENCE(req, prev_req, vifr_port_ipackets, diff_ms);
1596 0 : COMPUTE_DIFFERENCE(req, prev_req, vifr_port_ierrors, diff_ms);
1597 0 : COMPUTE_DIFFERENCE(req, prev_req, vifr_port_inombufs, diff_ms);
1598 :
1599 0 : COMPUTE_DIFFERENCE(req, prev_req, vifr_queue_ierrors, diff_ms);
1600 0 : COMPUTE_DIFFERENCE(req, prev_req, vifr_queue_ipackets, diff_ms);
1601 :
1602 0 : for (i = 0; i < req->vifr_queue_ierrors_to_lcore_size; i++) {
1603 0 : COMPUTE_DIFFERENCE(req, prev_req, vifr_queue_ierrors_to_lcore[i], diff_ms);
1604 : }
1605 :
1606 0 : COMPUTE_DIFFERENCE(req, prev_req, vifr_ibytes, diff_ms);
1607 0 : COMPUTE_DIFFERENCE(req, prev_req, vifr_ipackets, diff_ms);
1608 0 : COMPUTE_DIFFERENCE(req, prev_req, vifr_ierrors, diff_ms);
1609 :
1610 : /* TX */
1611 0 : COMPUTE_DIFFERENCE(req, prev_req, vifr_obytes, diff_ms);
1612 0 : COMPUTE_DIFFERENCE(req, prev_req, vifr_opackets, diff_ms);
1613 0 : COMPUTE_DIFFERENCE(req, prev_req, vifr_oerrors, diff_ms);
1614 :
1615 0 : COMPUTE_DIFFERENCE(req, prev_req, vifr_queue_oerrors, diff_ms);
1616 0 : COMPUTE_DIFFERENCE(req, prev_req, vifr_queue_opackets, diff_ms);
1617 :
1618 0 : COMPUTE_DIFFERENCE(req, prev_req, vifr_port_osyscalls, diff_ms);
1619 0 : COMPUTE_DIFFERENCE(req, prev_req, vifr_port_opackets, diff_ms);
1620 0 : COMPUTE_DIFFERENCE(req, prev_req, vifr_port_oerrors, diff_ms);
1621 :
1622 0 : COMPUTE_DIFFERENCE(req, prev_req, vifr_dev_obytes, diff_ms);
1623 0 : COMPUTE_DIFFERENCE(req, prev_req, vifr_dev_opackets, diff_ms);
1624 0 : COMPUTE_DIFFERENCE(req, prev_req, vifr_dev_oerrors, diff_ms);
1625 0 : }
1626 :
1627 : static void
1628 0 : rate_stats(struct nl_client *cl, unsigned int vr_op)
1629 : {
1630 : struct tm *tm;
1631 : time_t secs;
1632 0 : char fmt[80] = {0};
1633 0 : int ret = 0;
1634 0 : char kb_input[2] = {0};
1635 0 : struct winsize terminal_size = {0};
1636 0 : int local_ignore_number_interface = ignore_number_interface;
1637 0 : int local_print_number_interface = print_number_interface;
1638 0 : first_rate_iter = true;
1639 :
1640 : while (true) {
1641 0 : while (!is_stdin_hit() || get_set) {
1642 0 : ignore_number_interface = local_ignore_number_interface;
1643 0 : gettimeofday(&last_time, NULL);
1644 0 : first_rate_iter || usleep(SET_TIMEOUT_MS * 1000);
1645 : /* Get terminal parameters. */
1646 0 : ioctl(STDOUT_FILENO, TIOCGWINSZ, &terminal_size);
1647 :
1648 0 : print_number_interface = (terminal_size.ws_row - 9) / LISTING_NUM_OF_LINE ;
1649 0 : print_number_interface =
1650 0 : (print_number_interface > MAX_OUTPUT_IF? MAX_OUTPUT_IF: print_number_interface);
1651 0 : local_print_number_interface = print_number_interface;
1652 0 : if (print_number_interface <= 0) {
1653 0 : printf("Size of terminal is too small.\n");
1654 0 : first_rate_iter = true;
1655 0 : continue;
1656 : }
1657 0 : ret = system(CLEAN_SCREEN_CMD);
1658 0 : if (ret == -1) {
1659 0 : fprintf(stderr, "Error: system() failed.\n");
1660 0 : exit(1);
1661 : }
1662 0 : printf("Interface rate statistics\n");
1663 0 : printf("-------------------------\n\n");
1664 0 : if (vr_intf_op(cl, vr_op)) {
1665 0 : fprintf(stderr, "Communication problem with vRouter.\n\n");
1666 0 : exit(1);
1667 : }
1668 0 : if(list_set) {
1669 0 : printf("Key 'q' for quit, key 'k' for previous page, key 'j' for next page.\n");
1670 : }
1671 0 : secs = last_time.tv_sec;
1672 0 : tm = localtime(&secs);
1673 0 : if (tm) {
1674 0 : strftime(fmt, sizeof(fmt), "%Y-%m-%d %H:%M:%S %z", tm);
1675 0 : printf("%s \n", fmt);
1676 : }
1677 :
1678 : /* We need reinitialize dump_marker variable, because we are in loop */
1679 0 : dump_marker = -1;
1680 0 : first_rate_iter = false;
1681 : }
1682 :
1683 : /*
1684 : * We must get minimum 2 characters,
1685 : * otherwise we will be in outer loop, always.
1686 : */
1687 : /* To suppress the warning return if EOF. */
1688 0 : if (fgets(kb_input, 2, stdin) == NULL)
1689 0 : return;
1690 :
1691 0 : switch (tolower(kb_input[0])) {
1692 0 : case 'q':
1693 0 : return;
1694 :
1695 0 : case 'k':
1696 0 : local_ignore_number_interface =
1697 0 : (local_ignore_number_interface - local_print_number_interface <= 0)?
1698 : 0:
1699 : (local_ignore_number_interface - local_print_number_interface);
1700 0 : break;
1701 :
1702 0 : case 'j':
1703 0 : local_ignore_number_interface =
1704 : (local_ignore_number_interface + local_print_number_interface);
1705 0 : break;
1706 :
1707 0 : default:
1708 0 : break;
1709 : }
1710 0 : fflush(NULL);
1711 : }
1712 : }
1713 :
1714 : static int
1715 0 : is_stdin_hit()
1716 : {
1717 : struct timeval tv;
1718 : fd_set fds;
1719 :
1720 0 : tv.tv_sec = 0;
1721 0 : tv.tv_usec = 0;
1722 :
1723 0 : FD_ZERO(&fds);
1724 0 : FD_SET(STDIN_FILENO, &fds);
1725 0 : select(STDIN_FILENO + 1, &fds, NULL, NULL, &tv);
1726 0 : return FD_ISSET(STDIN_FILENO, &fds);
1727 : }
1728 :
1729 : int
1730 12 : main(int argc, char *argv[])
1731 : {
1732 : int ret, opt, option_index;
1733 12 : unsigned int i = 0;
1734 :
1735 : static struct termios old_term_set, new_term_set;
1736 :
1737 : /*
1738 : * the proto of the socket changes based on whether we are creating an
1739 : * interface in linux or doing an operation in vrouter
1740 : */
1741 12 : unsigned int sock_proto = NETLINK_GENERIC;
1742 :
1743 12 : vif_fill_nl_callbacks();
1744 :
1745 12 : parse_ini_file();
1746 12 : platform = get_platform();
1747 :
1748 36 : while ((opt = getopt_long(argc, argv, "ba:c:d:g:klm:t:T:v:p:C:DPi:s:",
1749 36 : long_options, &option_index)) >= 0) {
1750 24 : switch (opt) {
1751 0 : case 'a':
1752 0 : add_set = 1;
1753 0 : parse_long_opts(ADD_OPT_INDEX, optarg);
1754 0 : break;
1755 :
1756 0 : case 'c':
1757 0 : create_set = 1;
1758 0 : parse_long_opts(CREATE_OPT_INDEX, optarg);
1759 0 : break;
1760 :
1761 0 : case 'd':
1762 0 : delete_set = 1;
1763 0 : parse_long_opts(DELETE_OPT_INDEX, optarg);
1764 0 : break;
1765 :
1766 0 : case 'g':
1767 0 : get_set = 1;
1768 0 : parse_long_opts(GET_OPT_INDEX, optarg);
1769 0 : break;
1770 :
1771 0 : case 'k':
1772 0 : kindex_set = 1;
1773 0 : parse_long_opts(KINDEX_OPT_INDEX, optarg);
1774 0 : break;
1775 :
1776 0 : case 'l':
1777 : case 'b':
1778 0 : list_set = 1;
1779 0 : parse_long_opts(LIST_OPT_INDEX, NULL);
1780 0 : break;
1781 :
1782 0 : case 'm':
1783 0 : mac_set = 1;
1784 0 : parse_long_opts(MAC_OPT_INDEX, optarg);
1785 0 : break;
1786 :
1787 0 : case 'v':
1788 0 : vrf_set = 1;
1789 0 : parse_long_opts(VRF_OPT_INDEX, optarg);
1790 0 : break;
1791 :
1792 0 : case 'p':
1793 0 : policy_set = 1;
1794 0 : parse_long_opts(POLICY_OPT_INDEX, NULL);
1795 0 : break;
1796 :
1797 0 : case 'D':
1798 0 : pmd_set = 1;
1799 0 : parse_long_opts(PMD_OPT_INDEX, NULL);
1800 0 : break;
1801 :
1802 0 : case 'P':
1803 0 : pci_set = 1;
1804 0 : parse_long_opts(PCI_OPT_INDEX, NULL);
1805 0 : break;
1806 :
1807 0 : case 't':
1808 0 : type_set = 1;
1809 0 : parse_long_opts(TYPE_OPT_INDEX, optarg);
1810 0 : break;
1811 :
1812 0 : case 'T':
1813 0 : transport_set = 1;
1814 0 : parse_long_opts(TRANSPORT_OPT_INDEX, optarg);
1815 0 : break;
1816 :
1817 0 : case 'i':
1818 0 : vindex_set = 1;
1819 0 : parse_long_opts(VINDEX_OPT_INDEX, NULL);
1820 0 : break;
1821 :
1822 0 : case 'C':
1823 0 : core_set = 1;
1824 0 : parse_long_opts(CORE_OPT_INDEX, optarg);
1825 0 : break;
1826 0 : case 's':
1827 0 : sock_dir_set = 1;
1828 0 : parse_long_opts(SOCK_DIR_OPT_INDEX, optarg);
1829 0 : break;
1830 24 : case 0:
1831 24 : parse_long_opts(option_index, optarg);
1832 24 : break;
1833 :
1834 0 : case '?':
1835 : default:
1836 0 : Usage();
1837 : }
1838 : }
1839 :
1840 12 : validate_options();
1841 :
1842 12 : sock_proto = VR_NETLINK_PROTO_DEFAULT;
1843 : #if defined(__linux__)
1844 12 : if (create_set)
1845 0 : sock_proto = NETLINK_ROUTE;
1846 : #endif
1847 :
1848 12 : if (sock_dir_set) {
1849 12 : set_platform_vtest();
1850 : /* Reinit platform variable since platform is changed to vtest now */
1851 12 : platform = get_platform();
1852 : }
1853 12 : cl = vr_get_nl_client(sock_proto);
1854 12 : if (!cl) {
1855 0 : printf("Error registering NetLink client: %s (%d)\n",
1856 0 : strerror(errno), errno);
1857 0 : exit(-ENOMEM);
1858 : }
1859 12 : if (add_set) {
1860 : /*
1861 : * for addition, we need to see whether the interface already
1862 : * exists in vrouter or not. so, get can return error if the
1863 : * interface does not exist in vrouter
1864 : */
1865 0 : vr_ignore_nl_errors = true;
1866 0 : vr_intf_op(cl, SANDESH_OP_GET);
1867 0 : vr_ignore_nl_errors = false;
1868 : }
1869 12 : if (!rate_set) {
1870 12 : vr_intf_op(cl, vr_op);
1871 :
1872 : } else {
1873 0 : fcntl(STDIN_FILENO, F_SETFL, fcntl(STDIN_FILENO, F_GETFL) | O_NONBLOCK);
1874 : /*
1875 : * tc[get/set]attr functions are for changing terminal behavior.
1876 : * We dont have to write enter (newline) for getting character from terminal.
1877 : *
1878 : */
1879 0 : tcgetattr(STDIN_FILENO, &old_term_set);
1880 0 : new_term_set = old_term_set;
1881 0 : new_term_set.c_lflag &= ~(ICANON);
1882 0 : tcsetattr(STDIN_FILENO, TCSANOW, &new_term_set);
1883 :
1884 0 : rate_stats(cl, vr_op);
1885 0 : tcsetattr(STDIN_FILENO, TCSANOW, &old_term_set);
1886 0 : for (i = 0; i < VR_MAX_INTERFACES; i++) {
1887 0 : if (prev_req[i].vifr_queue_ierrors_to_lcore) {
1888 0 : free(prev_req[i].vifr_queue_ierrors_to_lcore);
1889 0 : prev_req[i].vifr_queue_ierrors_to_lcore = NULL;
1890 : }
1891 : }
1892 :
1893 : }
1894 12 : return 0;
1895 : }
|