ciscollm-cli 1.2.0 → 1.3.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -50,7 +50,31 @@ class ShellSimulator {
50
50
  shellFunctions = {};
51
51
  ospfEnabled = false;
52
52
  ospfProcessId = null;
53
+ ripEnabled = false;
54
+ ripVersion = 2;
55
+ ripAutoSummary = false;
56
+ bgpEnabled = false;
57
+ bgpAsn = null;
58
+ eigrpEnabled = false;
59
+ eigrpAsn = null;
60
+ vtpMode = 'server';
61
+ vtpDomain = null;
62
+ vtpPassword = null;
63
+ hsrpGroups = new Map();
64
+ vrrpGroups = new Map();
65
+ ntpServers = [];
66
+ snmpCommunities = [];
67
+ natInsideInterfaces = new Set();
68
+ natOutsideInterfaces = new Set();
69
+ natRules = [];
70
+ acls = new Map();
53
71
  ipRoutingEnabled = true;
72
+ featuresEnabled = new Set();
73
+ vpcDomainId = null;
74
+ vpcPeerKeepalive = null;
75
+ vnSegments = new Map();
76
+ vrfs = new Map();
77
+ activeVrf = null;
54
78
  flashFiles = new Set(['c2960-lanbasek9-mz.150-2.SE4.bin']);
55
79
  pendingCopyDest = null;
56
80
  backupState = null;
@@ -95,6 +119,9 @@ class ShellSimulator {
95
119
  case 'INTERFACE_CONFIG':
96
120
  return `${this.hostname}(config-if)# `;
97
121
  case 'OSPF_CONFIG':
122
+ case 'RIP_CONFIG':
123
+ case 'BGP_CONFIG':
124
+ case 'EIGRP_CONFIG':
98
125
  return `${this.hostname}(config-router)# `;
99
126
  case 'DHCP_CONFIG':
100
127
  return `${this.hostname}(config-dhcp)# `;
@@ -102,6 +129,12 @@ class ShellSimulator {
102
129
  return `${this.hostname}(config-ext-nacl)# `;
103
130
  case 'VLAN_CONFIG':
104
131
  return `${this.hostname}(config-vlan)# `;
132
+ case 'VPC_CONFIG':
133
+ return `${this.hostname}(config-vpc-domain)# `;
134
+ case 'VRF_CONFIG':
135
+ return `${this.hostname}(config-vrf)# `;
136
+ case 'VRF_AF_CONFIG':
137
+ return `${this.hostname}(config-vrf-af-ipv4)# `;
105
138
  default:
106
139
  return `${this.hostname}# `;
107
140
  }
@@ -143,56 +176,57 @@ class ShellSimulator {
143
176
  }
144
177
  const args = commandToExecute.split(/\s+/);
145
178
  const cmd = args[0].toLowerCase();
179
+ const isShow = cmd === 'show' || cmd === 'sh' || (cmd === 'do' && (args[1]?.toLowerCase() === 'show' || args[1]?.toLowerCase() === 'sh'));
146
180
  if (cmd === '?' || cmd === 'help') {
147
181
  if (cmd === 'help') {
148
- return `Help may be requested at any point in a command by entering
149
- a question mark '?'. If nothing matches, the help list will
182
+ return `Help may be requested at any point in a command by entering
183
+ a question mark '?'. If nothing matches, the help list will
150
184
  show the available options.`;
151
185
  }
152
186
  if (this.mode === 'USER_EXEC') {
153
- return `Exec commands:
154
- disable Turn off privileged commands
155
- enable Turn on privileged commands
156
- exit Exit from the EXEC
157
- ping Send echo messages
187
+ return `Exec commands:
188
+ disable Turn off privileged commands
189
+ enable Turn on privileged commands
190
+ exit Exit from the EXEC
191
+ ping Send echo messages
158
192
  show Show running system information`;
159
193
  }
160
194
  else if (this.mode === 'PRIVILEGED_EXEC') {
161
- return `Exec commands:
162
- clear Reset functions
163
- configure Enter configuration mode
164
- copy Copy from one file to another
165
- dir List files on a filesystem
166
- disable Turn off privileged commands
167
- enable Turn on privileged commands
168
- exit Exit from the EXEC
169
- ping Send echo messages
170
- show Show running system information
195
+ return `Exec commands:
196
+ clear Reset functions
197
+ configure Enter configuration mode
198
+ copy Copy from one file to another
199
+ dir List files on a filesystem
200
+ disable Turn off privileged commands
201
+ enable Turn on privileged commands
202
+ exit Exit from the EXEC
203
+ ping Send echo messages
204
+ show Show running system information
171
205
  write Write running configuration to memory or terminal`;
172
206
  }
173
207
  else if (this.mode === 'GLOBAL_CONFIG') {
174
- return `Configure commands:
175
- do To run EXEC commands in config mode
176
- end Exit from configure mode
177
- exit Exit from configure mode
178
- hostname Set system's network name
179
- interface Select an interface to configure
180
- ip Global IP configuration subcommands
181
- no Negate a command or set defaults
182
- router Enable a routing process
208
+ return `Configure commands:
209
+ do To run EXEC commands in config mode
210
+ end Exit from configure mode
211
+ exit Exit from configure mode
212
+ hostname Set system's network name
213
+ interface Select an interface to configure
214
+ ip Global IP configuration subcommands
215
+ no Negate a command or set defaults
216
+ router Enable a routing process
183
217
  vlan Vlan configuration commands`;
184
218
  }
185
219
  else if (this.mode === 'INTERFACE_CONFIG') {
186
- return `Interface configuration commands:
187
- description Detailed description of this interface
188
- exit Exit from interface configuration mode
189
- ip IP interface configuration subcommands
190
- no Negate a command or set defaults
220
+ return `Interface configuration commands:
221
+ description Detailed description of this interface
222
+ exit Exit from interface configuration mode
223
+ ip IP interface configuration subcommands
224
+ no Negate a command or set defaults
191
225
  shutdown Shutdown this interface`;
192
226
  }
193
227
  else {
194
- return `Commands:
195
- exit Exit current mode
228
+ return `Commands:
229
+ exit Exit current mode
196
230
  end Exit to privileged EXEC mode`;
197
231
  }
198
232
  }
@@ -203,10 +237,15 @@ show the available options.`;
203
237
  return `% Incomplete command.`;
204
238
  }
205
239
  if (cmd === 'exit') {
206
- if (this.mode === 'INTERFACE_CONFIG' || this.mode === 'OSPF_CONFIG' || this.mode === 'DHCP_CONFIG' || this.mode === 'ACL_CONFIG' || this.mode === 'VLAN_CONFIG') {
240
+ if (this.mode === 'INTERFACE_CONFIG' || this.mode === 'OSPF_CONFIG' || this.mode === 'RIP_CONFIG' || this.mode === 'BGP_CONFIG' || this.mode === 'EIGRP_CONFIG' || this.mode === 'DHCP_CONFIG' || this.mode === 'ACL_CONFIG' || this.mode === 'VLAN_CONFIG' || this.mode === 'VPC_CONFIG' || this.mode === 'VRF_CONFIG') {
207
241
  this.mode = 'GLOBAL_CONFIG';
208
242
  this.activeInterface = null;
209
243
  this.activeVlan = null;
244
+ this.activeVrf = null;
245
+ return '';
246
+ }
247
+ else if (this.mode === 'VRF_AF_CONFIG') {
248
+ this.mode = 'VRF_CONFIG';
210
249
  return '';
211
250
  }
212
251
  else if (this.mode === 'GLOBAL_CONFIG') {
@@ -226,6 +265,7 @@ show the available options.`;
226
265
  this.mode = 'PRIVILEGED_EXEC';
227
266
  this.activeInterface = null;
228
267
  this.activeVlan = null;
268
+ this.activeVrf = null;
229
269
  return '';
230
270
  }
231
271
  }
@@ -269,7 +309,35 @@ show the available options.`;
269
309
  this.shellEnabled = true;
270
310
  return '';
271
311
  }
272
- if (this.mode === 'GLOBAL_CONFIG') {
312
+ const isGeneralCommand = isShow || cmd === 'ping' || cmd === 'write' || cmd === 'wr' || cmd === 'copy' || cmd === 'dir' || cmd === 'test';
313
+ if (this.mode === 'GLOBAL_CONFIG' && !isGeneralCommand) {
314
+ if (cmd === 'feature' && args[1]) {
315
+ const featureName = args.slice(1).join(' ').toLowerCase();
316
+ this.featuresEnabled.add(featureName);
317
+ return '';
318
+ }
319
+ if (cmd === 'no' && args[1] === 'feature' && args[2]) {
320
+ const featureName = args.slice(2).join(' ').toLowerCase();
321
+ this.featuresEnabled.delete(featureName);
322
+ return '';
323
+ }
324
+ if (cmd === 'vpc' && args[1] === 'domain' && args[2]) {
325
+ const domainId = parseInt(args[2], 10);
326
+ if (!isNaN(domainId)) {
327
+ this.vpcDomainId = domainId;
328
+ this.mode = 'VPC_CONFIG';
329
+ return '';
330
+ }
331
+ }
332
+ if (cmd === 'vrf' && args[1] === 'context' && args[2]) {
333
+ const vrfName = args[2];
334
+ this.activeVrf = vrfName;
335
+ if (!this.vrfs.has(vrfName)) {
336
+ this.vrfs.set(vrfName, { routeTargets: [] });
337
+ }
338
+ this.mode = 'VRF_CONFIG';
339
+ return '';
340
+ }
273
341
  if (cmd === 'hostname' && args[1]) {
274
342
  this.hostname = args[1];
275
343
  return '';
@@ -345,6 +413,81 @@ show the available options.`;
345
413
  this.ospfProcessId = null;
346
414
  return '';
347
415
  }
416
+ if (cmd === 'router' && args[1] === 'rip') {
417
+ this.mode = 'RIP_CONFIG';
418
+ this.ripEnabled = true;
419
+ return '';
420
+ }
421
+ if (cmd === 'no' && args[1] === 'router' && args[2] === 'rip') {
422
+ this.ripEnabled = false;
423
+ return '';
424
+ }
425
+ if (cmd === 'router' && args[1] === 'bgp') {
426
+ this.mode = 'BGP_CONFIG';
427
+ this.bgpAsn = args[2] || null;
428
+ this.bgpEnabled = true;
429
+ return '';
430
+ }
431
+ if (cmd === 'no' && args[1] === 'router' && args[2] === 'bgp') {
432
+ this.bgpEnabled = false;
433
+ this.bgpAsn = null;
434
+ return '';
435
+ }
436
+ if (cmd === 'spanning-tree' && args[1]) {
437
+ return '';
438
+ }
439
+ if (cmd === 'router' && args[1] === 'eigrp') {
440
+ this.mode = 'EIGRP_CONFIG';
441
+ this.eigrpAsn = args[2] || null;
442
+ this.eigrpEnabled = true;
443
+ return '';
444
+ }
445
+ if (cmd === 'no' && args[1] === 'router' && args[2] === 'eigrp') {
446
+ this.eigrpEnabled = false;
447
+ this.eigrpAsn = null;
448
+ return '';
449
+ }
450
+ if (cmd === 'vtp' && args[1]) {
451
+ if (args[1] === 'mode' && args[2]) {
452
+ this.vtpMode = args[2].toLowerCase();
453
+ }
454
+ else if (args[1] === 'domain' && args[2]) {
455
+ this.vtpDomain = args[2];
456
+ }
457
+ else if (args[1] === 'password' && args[2]) {
458
+ this.vtpPassword = args[2];
459
+ }
460
+ return '';
461
+ }
462
+ if (cmd === 'ntp' && args[1] === 'server' && args[2]) {
463
+ if (!this.ntpServers.includes(args[2])) {
464
+ this.ntpServers.push(args[2]);
465
+ }
466
+ return '';
467
+ }
468
+ if (cmd === 'snmp-server' && args[1] === 'community' && args[2]) {
469
+ if (!this.snmpCommunities.includes(args[2])) {
470
+ this.snmpCommunities.push(args[2]);
471
+ }
472
+ return '';
473
+ }
474
+ if (cmd === 'ip' && args[1] === 'nat' && args[2] === 'inside' && args[3] === 'source') {
475
+ this.natRules.push(args.slice(2).join(' '));
476
+ return '';
477
+ }
478
+ if (cmd === 'access-list' && args[1] && args[2]) {
479
+ const aclId = args[1];
480
+ const rule = args.slice(2).join(' ');
481
+ if (!this.acls.has(aclId)) {
482
+ this.acls.set(aclId, []);
483
+ }
484
+ this.acls.get(aclId).push(rule);
485
+ return '';
486
+ }
487
+ if (cmd === 'ip' && args[1] === 'access-list' && (args[2] === 'standard' || args[2] === 'extended') && args[3]) {
488
+ this.mode = 'ACL_CONFIG';
489
+ return '';
490
+ }
348
491
  if (cmd === 'ip' && args[1] === 'dhcp' && args[2] === 'pool' && args[3]) {
349
492
  this.mode = 'DHCP_CONFIG';
350
493
  return '';
@@ -361,7 +504,7 @@ show the available options.`;
361
504
  }
362
505
  return `% Invalid input detected at '^' marker.`;
363
506
  }
364
- if (this.mode === 'VLAN_CONFIG' && this.activeVlan !== null) {
507
+ if (this.mode === 'VLAN_CONFIG' && this.activeVlan !== null && !isGeneralCommand) {
365
508
  if (cmd === 'name' && args[1]) {
366
509
  this.vlanNames.set(this.activeVlan, args.slice(1).join(' '));
367
510
  return '';
@@ -370,10 +513,40 @@ show the available options.`;
370
513
  this.vlanNames.set(this.activeVlan, `VLAN${this.activeVlan.toString().padStart(4, '0')}`);
371
514
  return '';
372
515
  }
516
+ if (cmd === 'vn-segment' && args[1]) {
517
+ const vni = parseInt(args[1], 10);
518
+ if (!isNaN(vni)) {
519
+ this.vnSegments.set(this.activeVlan, vni);
520
+ return '';
521
+ }
522
+ }
373
523
  return `% Invalid input detected at '^' marker.`;
374
524
  }
375
- if (this.mode === 'INTERFACE_CONFIG' && this.activeInterface) {
525
+ if (this.mode === 'INTERFACE_CONFIG' && this.activeInterface && !isGeneralCommand) {
376
526
  const iface = this.interfaces.get(this.activeInterface);
527
+ if (cmd === 'vpc' && args[1]) {
528
+ const vpcId = parseInt(args[1], 10);
529
+ if (!isNaN(vpcId)) {
530
+ iface.vpcMemberId = vpcId;
531
+ return '';
532
+ }
533
+ }
534
+ if (cmd === 'source-interface' && args[1]) {
535
+ iface.sourceInterface = args[1];
536
+ return '';
537
+ }
538
+ if (cmd === 'member' && args[1] === 'vni' && args[2]) {
539
+ const vni = parseInt(args[2], 10);
540
+ if (!isNaN(vni)) {
541
+ if (!iface.memberVnis) {
542
+ iface.memberVnis = new Map();
543
+ }
544
+ const mcastGroup = args[3] === 'mcast-group' ? args[4] : undefined;
545
+ const associateVrf = args.includes('associate-vrf');
546
+ iface.memberVnis.set(vni, { mcastGroup, associateVrf });
547
+ return '';
548
+ }
549
+ }
377
550
  if (cmd === 'shutdown') {
378
551
  iface.adminShutdown = true;
379
552
  iface.lineProtocolUp = false;
@@ -449,9 +622,61 @@ show the available options.`;
449
622
  if (cmd === 'ip' && args[1] === 'ospf') {
450
623
  return '';
451
624
  }
625
+ if (cmd === 'switchport' && args[1] === 'mode' && args[2] === 'trunk') {
626
+ iface.switchportMode = 'trunk';
627
+ iface.isSwitchport = true;
628
+ return '';
629
+ }
630
+ if (cmd === 'switchport' && args[1] === 'trunk' && args[2] === 'allowed' && args[3] === 'vlan') {
631
+ return '';
632
+ }
633
+ if (cmd === 'channel-group' && args[1] && args[2] === 'mode' && args[3]) {
634
+ return '';
635
+ }
636
+ if (cmd === 'standby' && args[1]) {
637
+ const group = args[1];
638
+ if (!this.hsrpGroups.has(group)) {
639
+ this.hsrpGroups.set(group, { virtualIp: '', priority: 100, preempt: false });
640
+ }
641
+ const hsrp = this.hsrpGroups.get(group);
642
+ if (args[2] === 'ip' && args[3]) {
643
+ hsrp.virtualIp = args[3];
644
+ }
645
+ else if (args[2] === 'priority' && args[3]) {
646
+ hsrp.priority = parseInt(args[3], 10);
647
+ }
648
+ else if (args[2] === 'preempt') {
649
+ hsrp.preempt = true;
650
+ }
651
+ return '';
652
+ }
653
+ if (cmd === 'vrrp' && args[1]) {
654
+ const group = args[1];
655
+ if (!this.vrrpGroups.has(group)) {
656
+ this.vrrpGroups.set(group, { virtualIp: '', priority: 100 });
657
+ }
658
+ const vrrp = this.vrrpGroups.get(group);
659
+ if (args[2] === 'ip' && args[3]) {
660
+ vrrp.virtualIp = args[3];
661
+ }
662
+ else if (args[2] === 'priority' && args[3]) {
663
+ vrrp.priority = parseInt(args[3], 10);
664
+ }
665
+ return '';
666
+ }
667
+ if (cmd === 'ip' && args[1] === 'nat' && (args[2] === 'inside' || args[2] === 'outside')) {
668
+ iface.natType = args[2];
669
+ if (args[2] === 'inside') {
670
+ this.natInsideInterfaces.add(this.activeInterface);
671
+ }
672
+ else {
673
+ this.natOutsideInterfaces.add(this.activeInterface);
674
+ }
675
+ return '';
676
+ }
452
677
  return `% Invalid input detected at '^' marker.`;
453
678
  }
454
- if (this.mode === 'OSPF_CONFIG') {
679
+ if (this.mode === 'OSPF_CONFIG' && !isGeneralCommand) {
455
680
  if (cmd === 'network' || cmd === 'router-id') {
456
681
  return '';
457
682
  }
@@ -460,36 +685,179 @@ show the available options.`;
460
685
  }
461
686
  return `% Invalid input detected at '^' marker.`;
462
687
  }
463
- if (this.mode === 'DHCP_CONFIG') {
688
+ if (this.mode === 'RIP_CONFIG' && !isGeneralCommand) {
689
+ if (cmd === 'version' && (args[1] === '1' || args[1] === '2')) {
690
+ this.ripVersion = parseInt(args[1], 10);
691
+ return '';
692
+ }
693
+ if (cmd === 'no' && args[1] === 'auto-summary') {
694
+ this.ripAutoSummary = false;
695
+ return '';
696
+ }
697
+ if (cmd === 'auto-summary') {
698
+ this.ripAutoSummary = true;
699
+ return '';
700
+ }
701
+ if (cmd === 'network' && args[1]) {
702
+ return '';
703
+ }
704
+ if (cmd === 'passive-interface' || (cmd === 'no' && args[1] === 'passive-interface')) {
705
+ return '';
706
+ }
707
+ return `% Invalid input detected at '^' marker.`;
708
+ }
709
+ if (this.mode === 'BGP_CONFIG' && !isGeneralCommand) {
710
+ if (cmd === 'neighbor' && args[1]) {
711
+ return '';
712
+ }
713
+ if (cmd === 'no' && args[1] === 'neighbor' && args[2]) {
714
+ return '';
715
+ }
716
+ if (cmd === 'network' && args[1]) {
717
+ return '';
718
+ }
719
+ if (cmd === 'no' && args[1] === 'auto-summary') {
720
+ return '';
721
+ }
722
+ if (cmd === 'auto-summary') {
723
+ return '';
724
+ }
725
+ if (cmd === 'address-family' && args[1] === 'l2vpn' && args[2] === 'evpn') {
726
+ return '';
727
+ }
728
+ if (cmd === 'send-community') {
729
+ return '';
730
+ }
731
+ return `% Invalid input detected at '^' marker.`;
732
+ }
733
+ if (this.mode === 'VPC_CONFIG' && !isGeneralCommand) {
734
+ if (cmd === 'peer-keepalive' && args[1] === 'destination') {
735
+ this.vpcPeerKeepalive = commandToExecute;
736
+ return '';
737
+ }
738
+ if (cmd === 'system-priority' || cmd === 'role' || cmd === 'peer-gateway' || cmd === 'peer-switch') {
739
+ return '';
740
+ }
741
+ return `% Invalid input detected at '^' marker.`;
742
+ }
743
+ if (this.mode === 'VRF_CONFIG' && this.activeVrf && !isGeneralCommand) {
744
+ const vrf = this.vrfs.get(this.activeVrf);
745
+ if (cmd === 'vni' && args[1]) {
746
+ vrf.vni = parseInt(args[1], 10);
747
+ return '';
748
+ }
749
+ if (cmd === 'rd' && args[1]) {
750
+ vrf.rd = args.slice(1).join(' ');
751
+ return '';
752
+ }
753
+ if (cmd === 'address-family' && args[1] === 'ipv4' && args[2] === 'unicast') {
754
+ this.mode = 'VRF_AF_CONFIG';
755
+ return '';
756
+ }
757
+ return `% Invalid input detected at '^' marker.`;
758
+ }
759
+ if (this.mode === 'VRF_AF_CONFIG' && this.activeVrf && !isGeneralCommand) {
760
+ const vrf = this.vrfs.get(this.activeVrf);
761
+ if (cmd === 'route-target' && args[1] === 'both' && args[2]) {
762
+ vrf.routeTargets.push(args.slice(1).join(' '));
763
+ return '';
764
+ }
765
+ return `% Invalid input detected at '^' marker.`;
766
+ }
767
+ if (this.mode === 'EIGRP_CONFIG' && !isGeneralCommand) {
768
+ if (cmd === 'network' && args[1]) {
769
+ return '';
770
+ }
771
+ if (cmd === 'no' && args[1] === 'auto-summary') {
772
+ return '';
773
+ }
774
+ if (cmd === 'auto-summary') {
775
+ return '';
776
+ }
777
+ if (cmd === 'passive-interface' || (cmd === 'no' && args[1] === 'passive-interface')) {
778
+ return '';
779
+ }
780
+ return `% Invalid input detected at '^' marker.`;
781
+ }
782
+ if (this.mode === 'DHCP_CONFIG' && !isGeneralCommand) {
464
783
  if (cmd === 'network' || cmd === 'default-router' || cmd === 'dns-server') {
465
784
  return '';
466
785
  }
467
786
  return `% Invalid input detected at '^' marker.`;
468
787
  }
469
- if (this.mode === 'ACL_CONFIG') {
788
+ if (this.mode === 'ACL_CONFIG' && !isGeneralCommand) {
470
789
  if (cmd === 'permit' || cmd === 'deny') {
471
790
  return '';
472
791
  }
473
792
  return `% Invalid input detected at '^' marker.`;
474
793
  }
475
- const isShow = cmd === 'show' || cmd === 'sh' || (cmd === 'do' && (args[1]?.toLowerCase() === 'show' || args[1]?.toLowerCase() === 'sh'));
476
794
  if (isShow) {
477
795
  const showArgs = cmd === 'do' ? args.slice(2) : args.slice(1);
478
796
  const showCmd = showArgs[0]?.toLowerCase();
797
+ if (showCmd === 'vpc') {
798
+ const domainId = this.vpcDomainId || 10;
799
+ const peerStatus = this.vpcPeerKeepalive ? 'peer adjacency formed ok' : 'peer link not configured';
800
+ const keepaliveStatus = this.vpcPeerKeepalive ? 'peer is alive' : 'peer keep-alive not configured';
801
+ return `Legend:
802
+ (*) - local vPC is down, dynamic backup loop preventer
803
+
804
+ vPC domain id : ${domainId}
805
+ Peer status : ${peerStatus}
806
+ vPC keep-alive status : ${keepaliveStatus}
807
+ Configuration-consistency status : success
808
+ Per-vlan consistency status : success
809
+ Type-2 consistency status : success
810
+ vPC role : primary
811
+ Number of vPCs configured : ${Array.from(this.interfaces.values()).filter(i => i.vpcMemberId !== undefined).length}
812
+ Peer Gateway : Enabled
813
+ `;
814
+ }
815
+ if (showCmd === 'nve' && showArgs[1] === 'interface') {
816
+ const nveIface = Array.from(this.interfaces.values()).find(i => i.name.toLowerCase().startsWith('nve'));
817
+ if (!nveIface) {
818
+ return '% NVE interface is not configured';
819
+ }
820
+ const sourceInt = nveIface.sourceInterface || 'Loopback0';
821
+ return `Interface: ${nveIface.name}, State: Up, Encapsulation: VXLAN
822
+ Source-Interface: ${sourceInt} (10.0.0.1)
823
+ `;
824
+ }
825
+ if (showCmd === 'nve' && showArgs[1] === 'vni') {
826
+ const nveIface = Array.from(this.interfaces.values()).find(i => i.name.toLowerCase().startsWith('nve'));
827
+ if (!nveIface || !nveIface.memberVnis) {
828
+ return `Interface VNI Multicast-group State Mode vPC Dev\n` +
829
+ `--------- -------- ----------------- ----- ---- -------\n`;
830
+ }
831
+ let out = `Interface VNI Multicast-group State Mode vPC Dev\n` +
832
+ `--------- -------- ----------------- ----- ---- -------\n`;
833
+ for (const [vni, details] of nveIface.memberVnis.entries()) {
834
+ const mcast = details.mcastGroup || 'n/a';
835
+ out += `${nveIface.name.padEnd(9)} ${vni.toString().padEnd(8)} ${mcast.padEnd(17)} Up CP n/a\n`;
836
+ }
837
+ return out;
838
+ }
839
+ if (showCmd === 'bgp' && showArgs[1] === 'l2vpn' && showArgs[2] === 'evpn' && showArgs[3] === 'summary') {
840
+ const bgpAs = this.bgpAsn || '65000';
841
+ return `BGP summary information for VRF default, address family L2VPN EVPN
842
+ BGP router identifier 10.0.0.1, local AS number ${bgpAs}
843
+ Neighbor V AS MsgRcvd MsgSent TblVer InQ OutQ Up/Down State/PfxRcd
844
+ 10.0.0.2 4 ${bgpAs} 120 125 47 0 0 01:24:55 2
845
+ `;
846
+ }
479
847
  if (showCmd === 'version' || showCmd === 'ver') {
480
- return `Cisco IOS Software, C2960 Software (C2960-LANBASEK9-M), Version 15.0(2)SE4, RELEASE SOFTWARE (fc1)
481
- Technical Support: http://www.cisco.com/techsupport
482
- Copyright (c) 1986-2013 by Cisco Systems, Inc.
483
- Compiled Wed 26-Jun-13 02:49 by prod_rel_team
484
-
485
- ROM: Bootstrap program is 12.2(44)SE Version
486
- BOOTLDR: C2960 Boot Loader (C2960-HBOOT-M) Version 12.2(44)SE, RELEASE SOFTWARE (fc1)
487
-
488
- Switch1 uptime is 2 hours, 15 minutes
489
- System returned to ROM by power-on
490
- System image file is "flash:/c2960-lanbasek9-mz.150-2.SE4.bin"
491
-
492
- This product contains cryptographic features and is subject to Y...
848
+ return `Cisco IOS Software, C2960 Software (C2960-LANBASEK9-M), Version 15.0(2)SE4, RELEASE SOFTWARE (fc1)
849
+ Technical Support: http://www.cisco.com/techsupport
850
+ Copyright (c) 1986-2013 by Cisco Systems, Inc.
851
+ Compiled Wed 26-Jun-13 02:49 by prod_rel_team
852
+
853
+ ROM: Bootstrap program is 12.2(44)SE Version
854
+ BOOTLDR: C2960 Boot Loader (C2960-HBOOT-M) Version 12.2(44)SE, RELEASE SOFTWARE (fc1)
855
+
856
+ Switch1 uptime is 2 hours, 15 minutes
857
+ System returned to ROM by power-on
858
+ System image file is "flash:/c2960-lanbasek9-mz.150-2.SE4.bin"
859
+
860
+ This product contains cryptographic features and is subject to Y...
493
861
  `;
494
862
  }
495
863
  if (showCmd === 'ip' && showArgs[1]?.startsWith('int') && showArgs[2]?.startsWith('br')) {
@@ -526,6 +894,70 @@ This product contains cryptographic features and is subject to Y...
526
894
  out += `!\nend\n`;
527
895
  return out;
528
896
  }
897
+ if (showCmd === 'ip' && showArgs[1] === 'protocols') {
898
+ let out = '';
899
+ if (this.ospfEnabled) {
900
+ out += `Routing Protocol is "ospf ${this.ospfProcessId || '10'}"\n` +
901
+ ` Outgoing update filter list for all interfaces is not set\n` +
902
+ ` Incoming update filter list for all interfaces is not set\n` +
903
+ ` Router ID 192.168.1.254\n` +
904
+ ` Number of areas in this router is 1. 1 normal 0 stub 0 nssa\n` +
905
+ ` Routing for Networks:\n` +
906
+ ` 192.168.1.0/24 area 0\n` +
907
+ ` Routing Information Sources:\n` +
908
+ ` Gateway Distance Last Update\n` +
909
+ ` Distance: (default is 110)\n\n`;
910
+ }
911
+ if (this.ripEnabled) {
912
+ out += `Routing Protocol is "rip"\n` +
913
+ ` Sending updates every 30 seconds, next due in 15 seconds\n` +
914
+ ` Invalid 180 seconds, hold down 180, flushed 240\n` +
915
+ ` Outgoing update filter list for all interfaces is not set\n` +
916
+ ` Incoming update filter list for all interfaces is not set\n` +
917
+ ` Redistributing: rip\n` +
918
+ ` Default version control: send version ${this.ripVersion}, receive version ${this.ripVersion}\n` +
919
+ ` Interface Send Recv Triggered RIP Key-chain\n`;
920
+ for (const name of this.interfaces.keys()) {
921
+ out += ` ${name.padEnd(21)} ${this.ripVersion} ${this.ripVersion}\n`;
922
+ }
923
+ out += ` Automatic network summarization is ${this.ripAutoSummary ? 'in effect' : 'not in effect'}\n` +
924
+ ` Maximum path: 4\n` +
925
+ ` Routing for Networks:\n` +
926
+ ` 192.168.1.0\n` +
927
+ ` Routing Information Sources:\n` +
928
+ ` Gateway Distance Last Update\n` +
929
+ ` Distance: (default is 120)\n\n`;
930
+ }
931
+ if (this.bgpEnabled) {
932
+ out += `Routing Protocol is "bgp ${this.bgpAsn || '65000'}"\n` +
933
+ ` Outgoing update filter list for all interfaces is not set\n` +
934
+ ` Incoming update filter list for all interfaces is not set\n` +
935
+ ` IGP synchronization is disabled\n` +
936
+ ` Automatic route summarization is disabled\n` +
937
+ ` Routing Information Sources:\n` +
938
+ ` Gateway Distance Last Update\n` +
939
+ ` Distance: external 20 internal 200 local 200\n\n`;
940
+ }
941
+ if (this.eigrpEnabled) {
942
+ out += `Routing Protocol is "eigrp ${this.eigrpAsn || '100'}"\n` +
943
+ ` Outgoing update filter list for all interfaces is not set\n` +
944
+ ` Incoming update filter list for all interfaces is not set\n` +
945
+ ` Default networks being advertised:\n` +
946
+ ` 192.168.1.0\n` +
947
+ ` EIGRP-IPv4 Protocol for AS(${this.eigrpAsn || '100'})\n` +
948
+ ` Metric weight K1=1, K2=0, K3=1, K4=0, K5=0\n` +
949
+ ` NSF-aware route hold timer is 240s\n` +
950
+ ` Router-ID: 192.168.1.254\n` +
951
+ ` Topology Kisspoint limit: 100\n` +
952
+ ` Routing Information Sources:\n` +
953
+ ` Gateway Distance Last Update\n` +
954
+ ` Distance: internal 90 external 170\n\n`;
955
+ }
956
+ if (!out) {
957
+ out = '*** No routing protocols configured ***\n';
958
+ }
959
+ return out;
960
+ }
529
961
  if (showCmd === 'ip' && showArgs[1]?.startsWith('ro')) {
530
962
  if (!this.ipRoutingEnabled) {
531
963
  return '% IP routing table is not enabled';
@@ -576,17 +1008,79 @@ This product contains cryptographic features and is subject to Y...
576
1008
  return out;
577
1009
  }
578
1010
  if (showCmd === 'cdp' && showArgs[1]?.startsWith('ne')) {
579
- return `Capability Codes: R - Router, T - Trans Bridge, B - Source Route Bridge
580
- S - Switch, H - Host, I - IGMP, r - Repeater, P - Phone
581
-
582
- Device ID Local Intrfce Holdtme Capability Platform Port ID
583
- Switch2 Gig 0/1 125 S I WS-C2960- Gig 0/1
1011
+ return `Capability Codes: R - Router, T - Trans Bridge, B - Source Route Bridge
1012
+ S - Switch, H - Host, I - IGMP, r - Repeater, P - Phone
1013
+
1014
+ Device ID Local Intrfce Holdtme Capability Platform Port ID
1015
+ Switch2 Gig 0/1 125 S I WS-C2960- Gig 0/1
584
1016
  `;
585
1017
  }
1018
+ if (showCmd === 'vtp' && showArgs[1] === 'status') {
1019
+ return `VTP Version capability : 1 to 3\n` +
1020
+ `VTP version running : 1\n` +
1021
+ `VTP Operating Mode : ${this.vtpMode}\n` +
1022
+ `VTP Domain Name : ${this.vtpDomain || ''}\n` +
1023
+ `VTP Pruning Mode : Disabled\n` +
1024
+ `VTP V2 Mode : Disabled\n` +
1025
+ `VTP Traps Generation : Disabled\n` +
1026
+ `MD5 digest : 0x94 0xC2 0x6E 0x93 0xA3 0xE2 0xD4 0xFA \n` +
1027
+ `Configuration last modified by 0.0.0.0 at 0-0-00 00:00:00\n`;
1028
+ }
1029
+ if (showCmd === 'standby' && (showArgs[1] === 'brief' || !showArgs[1])) {
1030
+ let out = ' Preempt State Active Standby Virtual IP\n';
1031
+ for (const [group, hsrp] of this.hsrpGroups.entries()) {
1032
+ out += `Gi0/1 ${group.padEnd(6)} ${hsrp.priority.toString().padEnd(4)} ${hsrp.preempt ? 'P' : ' '} Active local unknown ${hsrp.virtualIp}\n`;
1033
+ }
1034
+ if (this.hsrpGroups.size === 0) {
1035
+ out = '*** No HSRP standby groups configured ***\n';
1036
+ }
1037
+ return out;
1038
+ }
1039
+ if (showCmd === 'vrrp' && (showArgs[1] === 'brief' || !showArgs[1])) {
1040
+ let out = 'Interface Grp Fip Pri Time Own Pre State Master addr Group addr\n';
1041
+ for (const [group, vrrp] of this.vrrpGroups.entries()) {
1042
+ out += `Gi0/1 ${group.padEnd(4)} 1 ${vrrp.priority.toString().padEnd(3)} 3.609 N Y Master local ${vrrp.virtualIp}\n`;
1043
+ }
1044
+ if (this.vrrpGroups.size === 0) {
1045
+ out = '*** No VRRP groups configured ***\n';
1046
+ }
1047
+ return out;
1048
+ }
1049
+ if (showCmd === 'ip' && showArgs[1] === 'nat' && showArgs[2] === 'translations') {
1050
+ let out = 'Pro Inside global Inside local Outside local Outside global\n';
1051
+ for (const rule of this.natRules) {
1052
+ out += `tcp 192.0.2.1:80 192.168.1.10:80 --- ---\n`;
1053
+ }
1054
+ if (this.natRules.length === 0) {
1055
+ out = '*** No NAT translations active ***\n';
1056
+ }
1057
+ return out;
1058
+ }
1059
+ if (showCmd === 'access-lists') {
1060
+ let out = '';
1061
+ for (const [aclId, rules] of this.acls.entries()) {
1062
+ out += `Standard IP access list ${aclId}\n`;
1063
+ rules.forEach((rule, idx) => {
1064
+ out += ` ${(idx + 1) * 10} ${rule}\n`;
1065
+ });
1066
+ }
1067
+ if (this.acls.size === 0) {
1068
+ out = '*** No access lists configured ***\n';
1069
+ }
1070
+ return out;
1071
+ }
1072
+ if (showCmd === 'ntp' && (showArgs[1] === 'status' || showArgs[1] === 'associations')) {
1073
+ if (this.ntpServers.length === 0) {
1074
+ return 'NTP is not enabled.\n';
1075
+ }
1076
+ let out = 'Clock is synchronized, stratum 2, reference is ' + this.ntpServers[0] + '\n';
1077
+ out += 'nominal freq is 250.0000 Hz, actual freq is 250.0000 Hz, precision is 2**24\n';
1078
+ return out;
1079
+ }
586
1080
  if (showCmd === 'lldp' && showArgs[1]?.startsWith('ne')) {
587
- return `Device ID Local Intf Hold-time Capability Port ID
588
- Switch2 Gi0/1 120 S Gi0/1
589
- Total entries displayed: 1
1081
+ return `Device ID Local Intf Hold-time Capability Port ID
1082
+ Switch2 Gi0/1 120 S Gi0/1
1083
+ Total entries displayed: 1
590
1084
  `;
591
1085
  }
592
1086
  return `% Unrecognized show command: show ${showArgs.join(' ')}`;
@@ -627,9 +1121,9 @@ Total entries displayed: 1
627
1121
  }
628
1122
  if (cmd === 'ping' && args[1]) {
629
1123
  const ip = args[1];
630
- return `Sending 5, 100-byte ICMP Echos to ${ip}, timeout is 2 seconds:
631
- !!!!!
632
- Success rate is 100 percent (5/5), round-trip min/avg/max = 1/1/4 ms
1124
+ return `Sending 5, 100-byte ICMP Echos to ${ip}, timeout is 2 seconds:
1125
+ !!!!!
1126
+ Success rate is 100 percent (5/5), round-trip min/avg/max = 1/1/4 ms
633
1127
  `;
634
1128
  }
635
1129
  if (cmd === 'test' && args[1] === 'trigger-syslog') {
@@ -677,6 +1171,21 @@ Success rate is 100 percent (5/5), round-trip min/avg/max = 1/1/4 ms
677
1171
  if (lower.startsWith('vl')) {
678
1172
  return 'Vlan' + name.substring(2);
679
1173
  }
1174
+ if (lower.startsWith('ethernet')) {
1175
+ return 'Ethernet' + name.substring(8);
1176
+ }
1177
+ if (lower.startsWith('eth')) {
1178
+ return 'Ethernet' + name.substring(3);
1179
+ }
1180
+ if (lower.startsWith('port-channel')) {
1181
+ return 'Port-channel' + name.substring(12);
1182
+ }
1183
+ if (lower.startsWith('po')) {
1184
+ return 'Port-channel' + name.substring(2);
1185
+ }
1186
+ if (lower.startsWith('nve')) {
1187
+ return 'Nve' + name.substring(3);
1188
+ }
680
1189
  return name;
681
1190
  }
682
1191
  shortenInterfaceName(name) {
@@ -684,7 +1193,10 @@ Success rate is 100 percent (5/5), round-trip min/avg/max = 1/1/4 ms
684
1193
  .replace('GigabitEthernet', 'Gi')
685
1194
  .replace('FastEthernet', 'Fa')
686
1195
  .replace('TenGigabitEthernet', 'Te')
687
- .replace('Loopback', 'Lo');
1196
+ .replace('Loopback', 'Lo')
1197
+ .replace('Ethernet', 'Eth')
1198
+ .replace('Port-channel', 'Po')
1199
+ .replace('Nve', 'Nve');
688
1200
  }
689
1201
  getPrefixLength(mask) {
690
1202
  const parts = mask.split('.').map(Number);