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