dsh-ensp 0.3.3 → 0.5.0
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.
- package/README.en.md +339 -0
- package/README.md +18 -3
- package/docs/UI-ANCHORS.md +7 -1
- package/package.json +4 -2
- package/scripts/gen-knowledge.mjs +161 -0
- package/src/cli/ensp.mjs +29 -1
- package/src/core/acceptance.mjs +20 -2
- package/src/core/build.mjs +14 -3
- package/src/core/compat.mjs +236 -227
- package/src/core/console.mjs +57 -17
- package/src/core/doctor.mjs +17 -14
- package/src/core/index.mjs +16 -2
- package/src/core/knowledge.json +412 -0
- package/src/core/knowledge.mjs +104 -0
- package/src/core/launcher.mjs +89 -9
- package/src/core/paths.mjs +190 -0
- package/src/core/provision.mjs +40 -4
- package/src/dsh/index.mjs +85 -2
- package/src/mcp/server.mjs +23 -0
package/src/core/console.mjs
CHANGED
|
@@ -166,6 +166,7 @@ export class ConsoleSession {
|
|
|
166
166
|
#prompt = null
|
|
167
167
|
#hostname = null
|
|
168
168
|
#closed = false
|
|
169
|
+
#closeReason = null
|
|
169
170
|
#waiters = new Set()
|
|
170
171
|
|
|
171
172
|
/**
|
|
@@ -182,10 +183,12 @@ export class ConsoleSession {
|
|
|
182
183
|
})
|
|
183
184
|
socket.on('close', () => {
|
|
184
185
|
this.#closed = true
|
|
186
|
+
this.#closeReason ??= 'the console connection was closed by the device'
|
|
185
187
|
for (const waiter of this.#waiters) waiter()
|
|
186
188
|
})
|
|
187
|
-
socket.on('error', () => {
|
|
189
|
+
socket.on('error', (err) => {
|
|
188
190
|
this.#closed = true
|
|
191
|
+
this.#closeReason ??= `console error: ${err?.message ?? err}`
|
|
189
192
|
for (const waiter of this.#waiters) waiter()
|
|
190
193
|
})
|
|
191
194
|
}
|
|
@@ -195,6 +198,19 @@ export class ConsoleSession {
|
|
|
195
198
|
return this.#prompt
|
|
196
199
|
}
|
|
197
200
|
|
|
201
|
+
/**
|
|
202
|
+
* The hostname learned from the user-view prompt.
|
|
203
|
+
*
|
|
204
|
+
* Internal callers must pass it to `viewOf`. Without it a hostname containing a
|
|
205
|
+
* dash (`SW2-ACCESS`) makes every system-view prompt look like a sub-view, and
|
|
206
|
+
* the config engine ends up retrying quit/system-view instead of working.
|
|
207
|
+
*
|
|
208
|
+
* @returns {string|null}
|
|
209
|
+
*/
|
|
210
|
+
get hostname() {
|
|
211
|
+
return this.#hostname
|
|
212
|
+
}
|
|
213
|
+
|
|
198
214
|
/** @returns {'user'|'system'|'sub'|null} */
|
|
199
215
|
get view() {
|
|
200
216
|
return viewOf(this.#prompt, this.#hostname)
|
|
@@ -205,6 +221,11 @@ export class ConsoleSession {
|
|
|
205
221
|
return this.#closed
|
|
206
222
|
}
|
|
207
223
|
|
|
224
|
+
/** @returns {string|null} why the console closed, when it closed unexpectedly. */
|
|
225
|
+
get closeReason() {
|
|
226
|
+
return this.#closeReason
|
|
227
|
+
}
|
|
228
|
+
|
|
208
229
|
/**
|
|
209
230
|
* Wait until `predicate()` is true, a new chunk arrives, or the timeout fires.
|
|
210
231
|
* @param {() => boolean} predicate
|
|
@@ -240,16 +261,17 @@ export class ConsoleSession {
|
|
|
240
261
|
* @param {number} settleMs
|
|
241
262
|
* @returns {Promise<string>} the transcript produced since the buffer was last cleared
|
|
242
263
|
*/
|
|
243
|
-
async #readToPrompt(timeoutMs, settleMs = 60) {
|
|
264
|
+
async #readToPrompt(timeoutMs, settleMs = 60, echo = null) {
|
|
244
265
|
const started = Date.now()
|
|
245
266
|
while (Date.now() - started < timeoutMs) {
|
|
246
267
|
if (this.#closed) break
|
|
247
268
|
const text = clean(this.#buf)
|
|
248
269
|
// A confirmation question wins over a stale prompt: answer it explicitly.
|
|
249
270
|
if (CONFIRM_RE.test(text.split('\n').slice(-3).join('\n'))) break
|
|
271
|
+
const sawEcho = !echo || text.includes(echo)
|
|
250
272
|
// A pager stop is a terminal state too: nothing more will arrive until we
|
|
251
273
|
// send a key, so waiting for a prompt here would burn the whole timeout.
|
|
252
|
-
if (PROMPT_RE.test(text) || PAGER_RE.test(text.trimEnd())) {
|
|
274
|
+
if (sawEcho && (PROMPT_RE.test(text) || PAGER_RE.test(text.trimEnd()))) {
|
|
253
275
|
const before = this.#buf.length
|
|
254
276
|
await this.#waitUntil(() => this.#buf.length !== before || this.#closed, settleMs)
|
|
255
277
|
if (this.#buf.length === before) break
|
|
@@ -257,14 +279,23 @@ export class ConsoleSession {
|
|
|
257
279
|
// Poll the buffer rather than sleeping a fixed slice: most commands reply
|
|
258
280
|
// in a few milliseconds, and waiting 200 ms per line dominates the runtime
|
|
259
281
|
// of a 300-line config.
|
|
260
|
-
await this.#waitUntil(() =>
|
|
282
|
+
await this.#waitUntil(() => {
|
|
283
|
+
if (this.#closed) return true
|
|
284
|
+
const now = clean(this.#buf)
|
|
285
|
+
if (echo && !now.includes(echo)) return false
|
|
286
|
+
return PROMPT_RE.test(now) || PAGER_RE.test(now.trimEnd())
|
|
287
|
+
}, 25)
|
|
261
288
|
}
|
|
262
289
|
}
|
|
263
290
|
const text = clean(this.#buf)
|
|
264
291
|
this.#buf = ''
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
292
|
+
// The *last* prompt in the transcript is the current one. Matching with an
|
|
293
|
+
// `m` anchor and taking the first hit returns a prompt from the middle of the
|
|
294
|
+
// output, which is how a reply that still carried the previous prompt made the
|
|
295
|
+
// session believe it stood one view higher than it did.
|
|
296
|
+
const promptAt = [...text.matchAll(/[<\[][\w~\-./:]*[>\]]/g)].pop()
|
|
297
|
+
if (promptAt) {
|
|
298
|
+
this.#prompt = promptAt[0].trim()
|
|
268
299
|
// Learn the hostname the first time we see the user-view prompt; it is the
|
|
269
300
|
// only reliable anchor for telling `[R1-TEST]` (system) from `[R1-TEST-GE0/0/0]`.
|
|
270
301
|
this.#hostname ??= hostnameOf(this.#prompt)
|
|
@@ -301,16 +332,11 @@ export class ConsoleSession {
|
|
|
301
332
|
|
|
302
333
|
this.#buf = ''
|
|
303
334
|
this.#line(command)
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
const echoed = output.includes(command.split(/\s+/)[0])
|
|
310
|
-
if (!echoed) {
|
|
311
|
-
output += await this.#readToPrompt(timeoutMs, 100)
|
|
312
|
-
}
|
|
313
|
-
}
|
|
335
|
+
// VRP echoes the command before it answers. Requiring that echo makes the
|
|
336
|
+
// prompt trustworthy: otherwise a prompt left over from the previous command
|
|
337
|
+
// can satisfy the match and the caller then acts on the wrong view.
|
|
338
|
+
const echo = command.split(/\s+/)[0]
|
|
339
|
+
let output = await this.#readToPrompt(timeoutMs, entersView ? 200 : 60, echo)
|
|
314
340
|
|
|
315
341
|
// Answer at most one confirmation round; `save` and `reset` both use one.
|
|
316
342
|
if (CONFIRM_RE.test(output) && !PROMPT_RE.test(output.trimEnd())) {
|
|
@@ -332,6 +358,20 @@ export class ConsoleSession {
|
|
|
332
358
|
// the previous line so the caller sees what paging disabled would have shown.
|
|
333
359
|
if (pages > 0) output = stitchPages(output)
|
|
334
360
|
|
|
361
|
+
// A console that closed mid-command produced no output, and no output looks
|
|
362
|
+
// exactly like a command that succeeded and printed nothing. Report the
|
|
363
|
+
// closed socket instead of handing the caller a silent empty success.
|
|
364
|
+
if (this.#closed) {
|
|
365
|
+
return {
|
|
366
|
+
command,
|
|
367
|
+
ok: false,
|
|
368
|
+
error: this.#closeReason || 'the console connection closed before the reply arrived',
|
|
369
|
+
prompt: this.#prompt,
|
|
370
|
+
view: this.view,
|
|
371
|
+
output,
|
|
372
|
+
}
|
|
373
|
+
}
|
|
374
|
+
|
|
335
375
|
const errorMatch = output.match(ERROR_RE)
|
|
336
376
|
const prompt = this.#prompt
|
|
337
377
|
return {
|
package/src/core/doctor.mjs
CHANGED
|
@@ -21,11 +21,9 @@ import path from 'node:path'
|
|
|
21
21
|
import { checkTopologySupport, probeDevice } from './compat.mjs'
|
|
22
22
|
import { DEFAULT_ANCHORS, calibrateAnchors } from './calibrate.mjs'
|
|
23
23
|
import { enspPid, locateWindow } from './launcher.mjs'
|
|
24
|
+
import { probePaths, resolveEnspRoot } from './paths.mjs'
|
|
24
25
|
|
|
25
|
-
export const
|
|
26
|
-
export const DEFAULT_VBOX = 'E:\\VirtualBox\\VBoxManage.exe'
|
|
27
|
-
|
|
28
|
-
const MIN_FREE_MEMORY_MB = 1024
|
|
26
|
+
export const MIN_FREE_MEMORY_MB = 1024
|
|
29
27
|
|
|
30
28
|
/** PowerShell helper that answers "does synthetic input reach this session?". */
|
|
31
29
|
const INPUT_PROBE = String.raw`
|
|
@@ -172,33 +170,39 @@ function check(id, status, detail, fix) {
|
|
|
172
170
|
* @param {boolean} [options.deep] also run the input probe (slow: ~2 s)
|
|
173
171
|
*/
|
|
174
172
|
export function doctor(options = {}) {
|
|
175
|
-
const
|
|
176
|
-
const
|
|
177
|
-
const
|
|
173
|
+
const found = probePaths({ exe: options.exe, vbox: options.vbox })
|
|
174
|
+
const exe = found.ensp.path
|
|
175
|
+
const vbox = found.vbox.path
|
|
176
|
+
const root = options.root || resolveEnspRoot({ exe })
|
|
178
177
|
const deep = options.deep !== false
|
|
179
178
|
const checks = []
|
|
180
179
|
|
|
181
180
|
// 1. eNSP client present
|
|
182
|
-
const exeOk = fs.existsSync(exe)
|
|
181
|
+
const exeOk = Boolean(exe) && fs.existsSync(exe)
|
|
183
182
|
checks.push(
|
|
184
183
|
check(
|
|
185
184
|
'ensp-installed',
|
|
186
185
|
exeOk ? 'pass' : 'fail',
|
|
187
|
-
exeOk ? exe :
|
|
186
|
+
exeOk ? exe : 'not found in any configured or default location',
|
|
188
187
|
exeOk
|
|
189
188
|
? undefined
|
|
190
|
-
: 'Install eNSP, or pass --exe with the
|
|
189
|
+
: 'Install eNSP, or pass --exe with the full path to eNSP_Client.exe, '
|
|
190
|
+
+ 'or set DSH_ENSP_EXE. Both the default install root and the Windows '
|
|
191
|
+
+ 'install registry were checked.',
|
|
191
192
|
),
|
|
192
193
|
)
|
|
193
194
|
|
|
194
195
|
// 2. VirtualBox present (eNSP cannot boot a single device without it)
|
|
195
|
-
const vboxOk = fs.existsSync(vbox)
|
|
196
|
+
const vboxOk = Boolean(vbox) && fs.existsSync(vbox)
|
|
196
197
|
checks.push(
|
|
197
198
|
check(
|
|
198
199
|
'virtualbox',
|
|
199
200
|
vboxOk ? 'pass' : 'fail',
|
|
200
|
-
vboxOk ? vbox :
|
|
201
|
-
vboxOk
|
|
201
|
+
vboxOk ? vbox : 'not found in PATH or any default location',
|
|
202
|
+
vboxOk
|
|
203
|
+
? undefined
|
|
204
|
+
: 'Install VirtualBox 5.2.x, which ships with eNSP, or pass --vbox with '
|
|
205
|
+
+ 'the full path to VBoxManage.exe, or set DSH_VBOX.',
|
|
202
206
|
),
|
|
203
207
|
)
|
|
204
208
|
|
|
@@ -366,4 +370,3 @@ export function modelsOf(topology) {
|
|
|
366
370
|
}
|
|
367
371
|
|
|
368
372
|
/** Free-memory constant, exported so tests can assert against it. */
|
|
369
|
-
export { MIN_FREE_MEMORY_MB }
|
package/src/core/index.mjs
CHANGED
|
@@ -69,8 +69,6 @@ export {
|
|
|
69
69
|
freeMemoryMb,
|
|
70
70
|
busyConsolePorts,
|
|
71
71
|
modelsOf,
|
|
72
|
-
DEFAULT_ENSP_EXE,
|
|
73
|
-
DEFAULT_VBOX,
|
|
74
72
|
MIN_FREE_MEMORY_MB,
|
|
75
73
|
} from './doctor.mjs'
|
|
76
74
|
|
|
@@ -124,3 +122,19 @@ export {
|
|
|
124
122
|
renderScenario,
|
|
125
123
|
searchScenarios,
|
|
126
124
|
} from './presets.mjs'
|
|
125
|
+
|
|
126
|
+
export {
|
|
127
|
+
knowledgeTopics,
|
|
128
|
+
knowledgeFor,
|
|
129
|
+
searchKnowledge,
|
|
130
|
+
renderKnowledge,
|
|
131
|
+
} from './knowledge.mjs'
|
|
132
|
+
|
|
133
|
+
export {
|
|
134
|
+
resolveEnspExe,
|
|
135
|
+
resolveVBoxManage,
|
|
136
|
+
resolveEnspRoot,
|
|
137
|
+
probePaths,
|
|
138
|
+
enspCandidates,
|
|
139
|
+
vboxCandidates,
|
|
140
|
+
} from './paths.mjs'
|
|
@@ -0,0 +1,412 @@
|
|
|
1
|
+
{
|
|
2
|
+
"generatedFrom": "HCIP H12-821 单选/多选/判断题",
|
|
3
|
+
"sourceQuestions": 486,
|
|
4
|
+
"topics": {
|
|
5
|
+
"bgp": {
|
|
6
|
+
"scenarios": [
|
|
7
|
+
"bgp-ebgp-ibgp",
|
|
8
|
+
"bgp-route-reflector",
|
|
9
|
+
"bgp-attributes",
|
|
10
|
+
"bgp-aggregation",
|
|
11
|
+
"bgp-troubleshooting"
|
|
12
|
+
],
|
|
13
|
+
"points": [
|
|
14
|
+
{
|
|
15
|
+
"n": 313,
|
|
16
|
+
"q": "在BGP中非客户机角色既不是RR也不是客户机的IBGP设备,在AS内部非客户机与RR之间,以及所有的非客户机之间必须建立全连接关系",
|
|
17
|
+
"a": "A. 正确"
|
|
18
|
+
},
|
|
19
|
+
{
|
|
20
|
+
"n": 163,
|
|
21
|
+
"q": "在BGP中MED属性是一种度量值,用于向外部对等体指出进入本AS的首选路径。以下关于该属性的描述,正确的是哪些项?",
|
|
22
|
+
"a": "A. MED属性值越小则BGP路由越优 / C. 在IBGP对等体之间传递路由时,MED值会被保留并传递,除非部署了策略,否则MED值在传递过程中不发生改变也不会丢失 / D. MED被传递给EBGP对等体后,对等体在其AS内传递路由时,携带该MED值"
|
|
23
|
+
},
|
|
24
|
+
{
|
|
25
|
+
"n": 262,
|
|
26
|
+
"q": "在配置EBGP时,缺省情况下EBGP连接允许的最大跳数为1,即只能在物理直连链路上建立EBGP连接。",
|
|
27
|
+
"a": "A. 正确"
|
|
28
|
+
},
|
|
29
|
+
{
|
|
30
|
+
"n": 380,
|
|
31
|
+
"q": "BGP设备与对等体建立邻居关系后,会通告路由给邻居。以下关于BGP通告路由的描述,正确的是哪些项?",
|
|
32
|
+
"a": "A. 当存在多条到达同一目的地址的有效路由时,BGP设备只将最优路由发布给对等体 / C. 从EBGP对等体获取的路由,会发布给所有对等体 / D. 从IBGP对等体获取的路由,不会发送给IBGP对等体"
|
|
33
|
+
},
|
|
34
|
+
{
|
|
35
|
+
"n": 340,
|
|
36
|
+
"q": "在BGP中MED属性仅在相邻两个AS之间传递,收到此属性的AS一方不会再将其通告给任何其他第三方AS,同时,缺省情况下路由器只比较来自同一相邻AS的BGP路由的MED值,也就说如…",
|
|
37
|
+
"a": "A. 正确"
|
|
38
|
+
},
|
|
39
|
+
{
|
|
40
|
+
"n": 224,
|
|
41
|
+
"q": "如图所示,R1通告BGP路由给EBGP对等体,以下关于该过程的描述,正确的是哪些项?",
|
|
42
|
+
"a": "A. R2收到该路由传递给R3时,会保持路由的Next_Hop属性值不变 / B. 该路由中包含了这条路由的Origin属性 / C. R1只发送增量更新路由"
|
|
43
|
+
},
|
|
44
|
+
{
|
|
45
|
+
"n": 176,
|
|
46
|
+
"q": "在BGP网络中,建立EBGP邻居关系时,要使非直连的EBGP邻居正常建立,则必须包含以下哪些配置?",
|
|
47
|
+
"a": "A. peer connectinterface / B. peer as-number / C. peer ebgp-max-hop"
|
|
48
|
+
},
|
|
49
|
+
{
|
|
50
|
+
"n": 383,
|
|
51
|
+
"q": "以下哪些项属于BGP可选过渡属性?",
|
|
52
|
+
"a": "A. Aggregator / B. Community"
|
|
53
|
+
}
|
|
54
|
+
]
|
|
55
|
+
},
|
|
56
|
+
"security": {
|
|
57
|
+
"scenarios": [
|
|
58
|
+
"acl-filter",
|
|
59
|
+
"aaa-local",
|
|
60
|
+
"ipsec-vpn",
|
|
61
|
+
"firewall-zones",
|
|
62
|
+
"firewall-hrp",
|
|
63
|
+
"arp-security",
|
|
64
|
+
"dhcp-snooping"
|
|
65
|
+
],
|
|
66
|
+
"points": [
|
|
67
|
+
{
|
|
68
|
+
"n": 147,
|
|
69
|
+
"q": "ACL是路由常用匹配工具之一,并根据ACL规则功能的不同将ACL划分成多种类型,且每类ACL编号的取值范围不同。其中,编号范围为4000~4999,表示的是以下哪—类型ACL?",
|
|
70
|
+
"a": "C. 二层ACL"
|
|
71
|
+
},
|
|
72
|
+
{
|
|
73
|
+
"n": 195,
|
|
74
|
+
"q": "一台路由器收到报文后按照ACL匹配流程进行匹配时,匹配结果只有两种:“匹配”或“不匹配”。那么以下场景中,其返回匹配结果为“匹配”的是哪些项?",
|
|
75
|
+
"a": "B. 匹配了ACL,但匹配动作为“permit\" / C. 匹配了ACL,但匹配动作为“deny\""
|
|
76
|
+
},
|
|
77
|
+
{
|
|
78
|
+
"n": 247,
|
|
79
|
+
"q": "路由器配置访问控制列表时,可以通过ACL编号标识ACL,也可以通过名称来标识ACL。其中,配置命名型ACL时,需手工指定ACL的名字和ACL的编号。",
|
|
80
|
+
"a": "B. 错误"
|
|
81
|
+
},
|
|
82
|
+
{
|
|
83
|
+
"n": 235,
|
|
84
|
+
"q": "在路由器上配置ACL时,可通过指定一个唯一的数字标识该ACL,或通过名称代替编号来标识ACL。其中,命名型ACI一旦创建成功,用户便无法修改,只能删除该ACL,重新配置",
|
|
85
|
+
"a": "B. 错误"
|
|
86
|
+
},
|
|
87
|
+
{
|
|
88
|
+
"n": 93,
|
|
89
|
+
"q": "ACL是路由常用匹配工具之一,并根据ACL规则功能的不同将ACL划分成多种类型,且每类ACL编号的取值范围不同。其中,编号范围为4000~4999,表示的是以下哪一类型ACL?",
|
|
90
|
+
"a": "B. 二层ACL"
|
|
91
|
+
},
|
|
92
|
+
{
|
|
93
|
+
"n": 2,
|
|
94
|
+
"q": "在华为路由器上,若未配置ACL或配置了ACL但没有配置规则,那么它们返回ACL的匹配结果均为不匹配.",
|
|
95
|
+
"a": "A. TURE"
|
|
96
|
+
},
|
|
97
|
+
{
|
|
98
|
+
"n": 53,
|
|
99
|
+
"q": "使用ACL进行路由匹配时,不管是基本ACL还是高级ACL,或者是用户ACL,缺省情况下它们的ACL规则步长均为10。",
|
|
100
|
+
"a": "B. FALSE"
|
|
101
|
+
},
|
|
102
|
+
{
|
|
103
|
+
"n": 213,
|
|
104
|
+
"q": "某企业部署完IPSec后发现业务不通,经管理员排查发现没有数据流触发IKE协商,那么以下哪些原因可能导致该情况发生?",
|
|
105
|
+
"a": "A. 路由不可达 / B. ACL与保护数据流不匹配 / C. 域间安全策略配置错误 / D. IPSec策略未正确应用到相关接口"
|
|
106
|
+
}
|
|
107
|
+
]
|
|
108
|
+
},
|
|
109
|
+
"ospf": {
|
|
110
|
+
"scenarios": [
|
|
111
|
+
"ospf-single",
|
|
112
|
+
"ospf-multi-area",
|
|
113
|
+
"ospf-stub-nssa",
|
|
114
|
+
"ospf-lsa-types",
|
|
115
|
+
"ospf-virtual-link",
|
|
116
|
+
"ospf-troubleshooting"
|
|
117
|
+
],
|
|
118
|
+
"points": [
|
|
119
|
+
{
|
|
120
|
+
"n": 186,
|
|
121
|
+
"q": "某企业网络中,运行OSPF路由协议实现网络通信,已知某路由器角色仅为ABR,那么该设备可能产生以下哪些类型的LSA?",
|
|
122
|
+
"a": "A. Network Summary LSA / D. ASBR Summary LSA"
|
|
123
|
+
},
|
|
124
|
+
{
|
|
125
|
+
"n": 470,
|
|
126
|
+
"q": "以下关于配置OSPFStub区域注意事项的描述,正确的是哪一项?",
|
|
127
|
+
"a": "D. 如果将一个区域配置成为Stub区域,则该区域中的所有路由器都要配置Stub区域属性"
|
|
128
|
+
},
|
|
129
|
+
{
|
|
130
|
+
"n": 55,
|
|
131
|
+
"q": "某企业OSPF网络的NSSA区域引入了大量外部路由,现用户要求减少非特殊区域的LSA数量,那么该企业工程呵在NSSA区域中的ABR上,对由7类LSA转化成的5类LSA进行路由汇总。",
|
|
132
|
+
"a": "A. TURE"
|
|
133
|
+
},
|
|
134
|
+
{
|
|
135
|
+
"n": 382,
|
|
136
|
+
"q": "以下哪些方法能够相对降低OSPF路由计算负荷?",
|
|
137
|
+
"a": "A. 对普通区域路由手动汇总 / C. 部署Stub区域 / E. 划分OSPF非骨干区域"
|
|
138
|
+
},
|
|
139
|
+
{
|
|
140
|
+
"n": 439,
|
|
141
|
+
"q": "以下关于OSPFv3类LSA、4类LSA和5类LSA的描述,正确的是哪一项?",
|
|
142
|
+
"a": "C. 5类LSA在穿越不同区域后,不会发生改变,而3类LSA会发生变化"
|
|
143
|
+
},
|
|
144
|
+
{
|
|
145
|
+
"n": 339,
|
|
146
|
+
"q": "NSSA区域的ABR不会向NSSA泛洪4类和5类LSA,会将7类LSA转换成5类LSA泛洪给其他区域。",
|
|
147
|
+
"a": "A. 正确"
|
|
148
|
+
},
|
|
149
|
+
{
|
|
150
|
+
"n": 157,
|
|
151
|
+
"q": "在OSPF网络中,为减少某些区域的LSA数量,定义了多种特殊区域,如STUB、NSSA等。那么以下关于STUB区域的描述,正确的是哪些项?",
|
|
152
|
+
"a": "A. 虚连接不能穿越STUB区域 / C. STUB区域中的所有路由器都必须配置STUB区域属性"
|
|
153
|
+
},
|
|
154
|
+
{
|
|
155
|
+
"n": 266,
|
|
156
|
+
"q": "某企业办公网络中,运行了OSPF路由协议且划分了多个OSPF区域,为减少路由表规模和优化设备资源利用率,该企业网络工程师可在ASBR上执行路由汇总,减少区域间的三类LSA。",
|
|
157
|
+
"a": "B. 错误"
|
|
158
|
+
}
|
|
159
|
+
]
|
|
160
|
+
},
|
|
161
|
+
"reliability": {
|
|
162
|
+
"scenarios": [
|
|
163
|
+
"vrrp-basics",
|
|
164
|
+
"bfd-fast-convergence",
|
|
165
|
+
"firewall-hrp",
|
|
166
|
+
"dual-homed-isp"
|
|
167
|
+
],
|
|
168
|
+
"points": [
|
|
169
|
+
{
|
|
170
|
+
"n": 50,
|
|
171
|
+
"q": "如图所示,通过配置VRRP与BFD联动,当Backup设备通过BFD感知故障发生之后,等待Master Domn_Timer计时器超时后Backup设备会立即切换VRRP状态。",
|
|
172
|
+
"a": "B. 错误"
|
|
173
|
+
},
|
|
174
|
+
{
|
|
175
|
+
"n": 404,
|
|
176
|
+
"q": "VRRP协议包括两个版本VRRPV2和VRRPV3,以下关于VRRPV3版本的描述,正确的是哪些项?",
|
|
177
|
+
"a": "A. VRRPV3适用于IPv4和IPv6两种网络 / C. 设备的缺省优先级为100 / D. 缺省情况下,VRRP通告报文的发送时间间隔为1秒"
|
|
178
|
+
},
|
|
179
|
+
{
|
|
180
|
+
"n": 189,
|
|
181
|
+
"q": "某企业WLAN网络,为保证业务的可靠性,部署了VRRP双机热备。用户配置完成后,发现主备通道无法建立,导致双机热备份功能异常。那么造成上述故障的原因,可能是以下哪些?",
|
|
182
|
+
"a": "A. 主备服务报文的重传次数和重传间隔不一致 / C. 主备通道参数配置不匹配 / D. 本端的源IP地址、源端口号和对端的目的IP地址、目的端口号不一致"
|
|
183
|
+
},
|
|
184
|
+
{
|
|
185
|
+
"n": 412,
|
|
186
|
+
"q": "以下关于VRRP协议版本的描述,正确的是哪些项?",
|
|
187
|
+
"a": "A. VRRPv2仅适用于IPv4 / C. VRRPv3不支持认证 / D. VRRPv2支持认证"
|
|
188
|
+
},
|
|
189
|
+
{
|
|
190
|
+
"n": 324,
|
|
191
|
+
"q": "VRRP目前有两个版本,其中VRRPV2仅适用于IPV4网络,VRRPV3仅适用于IPv6网络。",
|
|
192
|
+
"a": "B. 错误"
|
|
193
|
+
},
|
|
194
|
+
{
|
|
195
|
+
"n": 181,
|
|
196
|
+
"q": "BFD作为一个快速故障检测机制,可以和多种协议进行联动。那么以下哪些协议支持和BFD进行联动?",
|
|
197
|
+
"a": "A. 静态路由 / B. BGP / C. OSPF / D. PIM"
|
|
198
|
+
},
|
|
199
|
+
{
|
|
200
|
+
"n": 342,
|
|
201
|
+
"q": "BFD提供了一个通用的、标准化的、介质无关的、协议无关的快速故障检测机制,如果想要通过该机制检测链路是否连通,两端设备必须都需要支持该特性。",
|
|
202
|
+
"a": "B. 错误"
|
|
203
|
+
},
|
|
204
|
+
{
|
|
205
|
+
"n": 182,
|
|
206
|
+
"q": "BFD的单臂回声功能是指通过BFD报文的环回操作检测链路的连通性,那么以下关于该功能的描述,正确的是哪些项?",
|
|
207
|
+
"a": "A. 单臂回声功能只适用于单跳BFD会话中 / B. 在对端使能了URPF特性的情况下,可能会导致BFD报文在对端被错误地丢弃 / C. 在配置单臂回声功能时,设备缺省使用出接口IP为源IP"
|
|
208
|
+
}
|
|
209
|
+
]
|
|
210
|
+
},
|
|
211
|
+
"isis": {
|
|
212
|
+
"scenarios": [
|
|
213
|
+
"isis-multi-level"
|
|
214
|
+
],
|
|
215
|
+
"points": [
|
|
216
|
+
{
|
|
217
|
+
"n": 14,
|
|
218
|
+
"q": "四台路由器运行is-is且已经建立邻接关系,区域号和路由器的等级如图中标记,下列说法中正确的有?",
|
|
219
|
+
"a": "A. R2和R3都会产生ATT置位的Level-1的LSP"
|
|
220
|
+
},
|
|
221
|
+
{
|
|
222
|
+
"n": 264,
|
|
223
|
+
"q": "在IS-IS网络中,Level-1路由器只能通过Level-1-2路由器接入IS-IS骨干区域从而访问其他区域。",
|
|
224
|
+
"a": "A. 正确"
|
|
225
|
+
},
|
|
226
|
+
{
|
|
227
|
+
"n": 234,
|
|
228
|
+
"q": "在IS-IS网络中,区域是根据路由器来划分的,一台路由器只能属于一个区域,因此IS-IS路由器只需要维护当前所在区域的LSDB即可。",
|
|
229
|
+
"a": "B. 错"
|
|
230
|
+
},
|
|
231
|
+
{
|
|
232
|
+
"n": 199,
|
|
233
|
+
"q": "在IS-IS网络中,路由器发送LSP报文交换链路状态信息,该报文分为Leve1-1LSP和Leve1-2LSP两种,且有着相同的报文格式。其中,LSP报文中的LSP ID由以下哪…",
|
|
234
|
+
"a": "A. System ID / B. LSP分片后的编号 / C. 伪节点JD"
|
|
235
|
+
},
|
|
236
|
+
{
|
|
237
|
+
"n": 375,
|
|
238
|
+
"q": "在广播型网络中,IS-IS协议会选举出一个DIS,而OSPF协议会选举出一个DR。那么以下关于DIS和DR区别的描述,正确的是哪些项?",
|
|
239
|
+
"a": "B. DIS和DR形成邻接关系的条件不同,IS-IS中的非DIS路由器之间也会建立邻接关系 / C. DIS和DR负责的功能不同,DIS主要用于创建和更新伪节点 / D. DIS和DR选举时间不同,DIS在建立完邻接关系之后选举"
|
|
240
|
+
},
|
|
241
|
+
{
|
|
242
|
+
"n": 173,
|
|
243
|
+
"q": "某园区网络中,全网运行IS-IS路由协议,现工程师在某一台设备上查看LSDB的详细信息如下所示。那么根据回显信息,以下描述正确的是哪些项?",
|
|
244
|
+
"a": "B. 该LSP来源的区域号为49.0123 / D. 该LSP源节点的系统lD为0100.0000.1001.00"
|
|
245
|
+
},
|
|
246
|
+
{
|
|
247
|
+
"n": 208,
|
|
248
|
+
"q": "在lS-IS网络中,每台路由器都可以产生LSP,那么当遇到以下哪些事件时,会触发生成一个新的LSP?",
|
|
249
|
+
"a": "A. 周期性更新 / B. IS-IS相关接口Up或Down / C. 区域间的IP路由发生变化 / D. 调大IS-IS接口开销值"
|
|
250
|
+
},
|
|
251
|
+
{
|
|
252
|
+
"n": 19,
|
|
253
|
+
"q": "在广播型IS-IS网络中,需要选举一个DIS来创建和更新伪节点。如图所示为某广播型IS-IS网络,在该场最下会被选举为DIS的是哪一台路由器?",
|
|
254
|
+
"a": "C. R3"
|
|
255
|
+
}
|
|
256
|
+
]
|
|
257
|
+
},
|
|
258
|
+
"switching": {
|
|
259
|
+
"scenarios": [
|
|
260
|
+
"vlan-access",
|
|
261
|
+
"trunk-interconnect",
|
|
262
|
+
"stp-rstp",
|
|
263
|
+
"mstp-load-balance",
|
|
264
|
+
"link-aggregation",
|
|
265
|
+
"super-vlan",
|
|
266
|
+
"port-security",
|
|
267
|
+
"port-isolation",
|
|
268
|
+
"stack-istack"
|
|
269
|
+
],
|
|
270
|
+
"points": [
|
|
271
|
+
{
|
|
272
|
+
"n": 250,
|
|
273
|
+
"q": "在RSTP网络中,如果一个接口收到一个RSTBPDU,发现自身缓存的RSTBPDU优于收到的RSTBPDU,则会直接丢弃收到的RSTBPDU,不做其他回应。",
|
|
274
|
+
"a": "B. 错误"
|
|
275
|
+
},
|
|
276
|
+
{
|
|
277
|
+
"n": 216,
|
|
278
|
+
"q": "在RSTP网络中,针对STP的不足,对端口角色进行了改进。那么RSTP可以包含以下哪些角色?",
|
|
279
|
+
"a": "A. Backup端 / B. 指定端口 / C. Alternate端 / D. 根端口"
|
|
280
|
+
},
|
|
281
|
+
{
|
|
282
|
+
"n": 137,
|
|
283
|
+
"q": "针对STP的不足,RSTP改变了配置BPDU的格式,充分利用了STP报文中的以下哪一字段,明确了端口角色?",
|
|
284
|
+
"a": "A. Flag"
|
|
285
|
+
},
|
|
286
|
+
{
|
|
287
|
+
"n": 167,
|
|
288
|
+
"q": "在RSTP网络中,新增了多种保护功能,如:根保护、环路保护、防TC-BPDU攻击等。那么以下关于RSTP新增保护功能的描述,正确的是哪些项?",
|
|
289
|
+
"a": "A. 某开启了根保护功能的指定接口收到优先级更高的RST BPDU时,一段时间内将无法转发报文 / C. 若设备开启BPDU保护功能后,会影响边缘端口的属性 / D. 启用防TC-BPDU攻击功能后,对于其他超出阈值的TC BPDU报文,定时器到期后设备只对其统一处理一次"
|
|
290
|
+
},
|
|
291
|
+
{
|
|
292
|
+
"n": 405,
|
|
293
|
+
"q": "某大型商场为防止广播域过大,导致网络性能变差,配置了VLAN Pool。网络工程师执行命令display vlan pool name STA的回显如下。那么以下关于该配置信息的…",
|
|
294
|
+
"a": "B. VLAN Pool的名称为STA / D. 加入到VLAN Pool的VLAN ID为2和4"
|
|
295
|
+
},
|
|
296
|
+
{
|
|
297
|
+
"n": 325,
|
|
298
|
+
"q": "在STP网络中,为了避免环路,指定端口选举完成后必须等待足够长的时间,使全网的端口状态全部确定后才能进行转发,针对STP上述问题,RSTP通过P/A机制加快了下游端口进人Forw…",
|
|
299
|
+
"a": "A. 正确"
|
|
300
|
+
},
|
|
301
|
+
{
|
|
302
|
+
"n": 236,
|
|
303
|
+
"q": "在STP网络中,若拓扑发生变更,必须先将拓扑变化信息传递给根桥,再由根桥向下泛洪拓扑变更信息。",
|
|
304
|
+
"a": "A. 对"
|
|
305
|
+
},
|
|
306
|
+
{
|
|
307
|
+
"n": 193,
|
|
308
|
+
"q": "若一个MST域内有多台交换机,那么在部署MSTP时,需要确保以下哪些参数必须一致?",
|
|
309
|
+
"a": "A. 域名 / B. VLAN与生成树实例的映射关系 / C. 都运行了MSTP功能 / D. MSTP修订级别"
|
|
310
|
+
}
|
|
311
|
+
]
|
|
312
|
+
},
|
|
313
|
+
"multicast": {
|
|
314
|
+
"scenarios": [
|
|
315
|
+
"multicast-pim-sm"
|
|
316
|
+
],
|
|
317
|
+
"points": [
|
|
318
|
+
{
|
|
319
|
+
"n": 345,
|
|
320
|
+
"q": "工程师配置组播协议之前,必须先使能IP组播路由功能,使能IP组播路由功能是配置一切组播功能的前提",
|
|
321
|
+
"a": "A. 正确"
|
|
322
|
+
},
|
|
323
|
+
{
|
|
324
|
+
"n": 223,
|
|
325
|
+
"q": "RPF检查是组播中一个极为重要的机制,可以确保转发路径的正确性和唯一性。正常情况下,RPF检查会从以下哪些路由表项中选出最优路由?",
|
|
326
|
+
"a": "A. MBGP路由表 / B. 单播路由表 / D. 组播静态路由表"
|
|
327
|
+
},
|
|
328
|
+
{
|
|
329
|
+
"n": 393,
|
|
330
|
+
"q": "作为IP传输三种方式之一,IP组播通信指的是IP报文从一个源发出,被转发到一组特定的接收者。以下关于IP组播技术的描述,正确的是哪些项?",
|
|
331
|
+
"a": "B. 相比广播,可以防止信息泛滥 / C. 相比广播,IP组播可以有效地节约网络带宽"
|
|
332
|
+
},
|
|
333
|
+
{
|
|
334
|
+
"n": 427,
|
|
335
|
+
"q": "以下关于IGMP SSM Mapping的描述,正确的是哪些项?",
|
|
336
|
+
"a": "A. SSM组播组的地址是232.0.0.0个232.255.255.255 / C. IGMP SSM Mapping通过静态的将组播源与组播组进行绑定,使得IGMPv1与IGMPv2的组成员也能接入SSM组播网络"
|
|
337
|
+
},
|
|
338
|
+
{
|
|
339
|
+
"n": 120,
|
|
340
|
+
"q": "IGMP有三个版本,不同版本支持的特性有所区别。以下哪一项是所有版本均支持的特性?",
|
|
341
|
+
"a": "C. 成员报告报文"
|
|
342
|
+
},
|
|
343
|
+
{
|
|
344
|
+
"n": 142,
|
|
345
|
+
"q": "在IPv4地址空间中,D类地址被用于组播。在D类地址范围内,以下哪一项属于为路由协议预留的永久组播地址?",
|
|
346
|
+
"a": "C. 224.0.0.0-224.0.0.255"
|
|
347
|
+
},
|
|
348
|
+
{
|
|
349
|
+
"n": 168,
|
|
350
|
+
"q": "IGMP组表项在组播转发中起到了重要的作用,某管理员通过命令查看一个组播表项信息如下。以下关于该表项的描述,正确的是哪些项?",
|
|
351
|
+
"a": "B. Expires代表了该组的老化时间 / C. 该表项是由用户主机发送的IGMP加入报文触发创建的 / D. 225.1.1.2是用户加入的组地址"
|
|
352
|
+
},
|
|
353
|
+
{
|
|
354
|
+
"n": 122,
|
|
355
|
+
"q": "某工程师在配置组播协议时未经过版本比对,结果设备配置的IGMP Snooping版本比用户主机的IGMP版本低。此时会发生以下哪一种情况?",
|
|
356
|
+
"a": "B. 用户无法收到组播数据,因为设备在收到IGMP Report报文后,只会向路由器端口转发,不会生成成员端口和转发表项"
|
|
357
|
+
}
|
|
358
|
+
]
|
|
359
|
+
},
|
|
360
|
+
"ipv6": {
|
|
361
|
+
"scenarios": [
|
|
362
|
+
"ipv6",
|
|
363
|
+
"ospfv3-ipv6"
|
|
364
|
+
],
|
|
365
|
+
"points": [
|
|
366
|
+
{
|
|
367
|
+
"n": 169,
|
|
368
|
+
"q": "IPv6在设计的时候考虑到IPv4的弊端,进行了改良和更新。相较于IPv4协议,IPv6协议具有以下哪些优势?",
|
|
369
|
+
"a": "A. IPv6协议内置支持通过地址自动配置方式使主机自动发现网络并获取IPv6地址 / B. 可实现QoS / C. 支持IPSec的认证和加密"
|
|
370
|
+
},
|
|
371
|
+
{
|
|
372
|
+
"n": 255,
|
|
373
|
+
"q": "在IPv6网络中,为了减少中间转发设备的处理压力,中间转发设备不对IPv6报文进行分片,报文的分片只在源节点进行",
|
|
374
|
+
"a": "A. 正确"
|
|
375
|
+
},
|
|
376
|
+
{
|
|
377
|
+
"n": 253,
|
|
378
|
+
"q": "某WLAN网络中,AC与AP为三层组网,且AC与AP均采用IPv6地址。此时AP可通过DHCPv6服务器响应报文中所携带的Option43字段来获取AC的IPv6地址fcO0:1…",
|
|
379
|
+
"a": "B. 错误"
|
|
380
|
+
},
|
|
381
|
+
{
|
|
382
|
+
"n": 220,
|
|
383
|
+
"q": "以下关于IPv6地址表示方法的描述,正确的是哪些项?",
|
|
384
|
+
"a": "A. 在一个IPv6地址中只能使用一次双冒号\"….\" / B. 每组中的前导“O”都可以省略"
|
|
385
|
+
},
|
|
386
|
+
{
|
|
387
|
+
"n": 374,
|
|
388
|
+
"q": "IPv6是网络层协议的第二代标准协议,也被称为lpng。以下关于它和IPv4比较的描述,正确的是哪些项?",
|
|
389
|
+
"a": "A. IPv6地址长度比IPV4大得多,拥有的地址规模也更为庞大 / D. IPv4没有安全件设计,而IPv6中支持到的安全"
|
|
390
|
+
}
|
|
391
|
+
]
|
|
392
|
+
},
|
|
393
|
+
"mpls": {
|
|
394
|
+
"scenarios": [
|
|
395
|
+
"mpls-basic",
|
|
396
|
+
"mpls-l3vpn"
|
|
397
|
+
],
|
|
398
|
+
"points": [
|
|
399
|
+
{
|
|
400
|
+
"n": 424,
|
|
401
|
+
"q": "作为网络管理员,可以使用下列哪些协议用于网络设备配置?",
|
|
402
|
+
"a": "B. SNMP / C. NETCONF / D. SSH"
|
|
403
|
+
},
|
|
404
|
+
{
|
|
405
|
+
"n": 436,
|
|
406
|
+
"q": "MPLS VPN网络一般由运营商搭建)VPN用户购买VPN服务来实现用户网络之间的数据互通。在MPLS VPN网络中存在诸多设备角色,其中以下哪一项设备角色是运营商网络中的骨干路…",
|
|
407
|
+
"a": "D. Provider"
|
|
408
|
+
}
|
|
409
|
+
]
|
|
410
|
+
}
|
|
411
|
+
}
|
|
412
|
+
}
|