@takodotid/circuit 0.43.1 → 1.0.0-rc.2
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.md +115 -37
- package/package.json +21 -58
- package/src/checks/across.ts +402 -0
- package/src/checks/built-in.ts +256 -0
- package/src/checks/device.ts +436 -0
- package/src/checks/index.ts +53 -0
- package/src/cli/advisories.ts +108 -0
- package/src/cli/app.ts +71 -0
- package/src/cli/editor-types.generated.ts +30 -0
- package/src/cli/editor-types.ts +69 -0
- package/src/cli/format.ts +124 -0
- package/src/cli/git-hooks.ts +79 -0
- package/src/cli/index.ts +350 -1170
- package/src/cli/migrate.ts +554 -0
- package/src/cli/project-commands.ts +656 -0
- package/src/cli/releases.ts +374 -0
- package/src/cli/remember.ts +339 -0
- package/src/cli/rename.ts +27 -33
- package/src/cli/secrets-password.ts +60 -0
- package/src/cli/secrets.ts +258 -0
- package/src/cli/setup.ts +300 -0
- package/src/cli/signing.ts +23 -0
- package/src/cli/text-editor.ts +268 -0
- package/src/cli/ui.ts +298 -0
- package/src/cli/version.ts +2 -0
- package/src/cli/versions.ts +158 -0
- package/src/config/address.ts +102 -0
- package/src/config/circuit.d.ts +30 -0
- package/src/config/common.ts +65 -0
- package/src/config/communities.ts +479 -0
- package/src/config/define.ts +684 -0
- package/src/config/device.ts +164 -0
- package/src/config/firewall.ts +150 -0
- package/src/config/index.ts +22 -0
- package/src/{schema → config}/interfaces.ts +121 -85
- package/src/config/keys.ts +434 -0
- package/src/config/management.ts +61 -0
- package/src/config/merge.ts +335 -0
- package/src/config/models.ts +70 -0
- package/src/config/monitoring.ts +64 -0
- package/src/config/network.ts +180 -0
- package/src/config/presets.ts +149 -0
- package/src/config/routing.ts +401 -0
- package/src/config/services.ts +51 -0
- package/src/config/switching.ts +84 -0
- package/src/config/system.ts +103 -0
- package/src/{schema → config}/time-zones.ts +1 -1
- package/src/core/address.ts +1 -1
- package/src/core/cabling.ts +8 -43
- package/src/core/graph.ts +40 -0
- package/src/{integrations → core}/registries.ts +5 -3
- package/src/core/secrets-file.ts +539 -0
- package/src/core/secrets.ts +83 -64
- package/src/core/topology.ts +103 -146
- package/src/core/utils.ts +12 -1
- package/src/model.ts +83 -0
- package/src/platforms/derive.ts +64 -37
- package/src/platforms/finding.ts +9 -0
- package/src/platforms/fortios/firewall.ts +76 -64
- package/src/platforms/fortios/index.ts +189 -125
- package/src/platforms/fortios/names.ts +51 -18
- package/src/platforms/fortios/render.ts +69 -62
- package/src/platforms/fortios/routing.ts +89 -58
- package/src/platforms/fortios/vdoms.ts +47 -16
- package/src/platforms/junos/TRAPS.md +2 -2
- package/src/platforms/junos/bgp.ts +63 -42
- package/src/platforms/junos/index.ts +122 -89
- package/src/platforms/junos/render.ts +139 -104
- package/src/platforms/platform.ts +10 -8
- package/src/platforms/raisecom-ros/TRAPS.md +1 -1
- package/src/platforms/raisecom-ros/index.ts +89 -70
- package/src/platforms/raisecom-ros/render.ts +49 -45
- package/src/platforms/routeros/TRAPS.md +3 -3
- package/src/platforms/routeros/index.ts +121 -60
- package/src/platforms/routeros/render.ts +214 -195
- package/src/platforms/vrp/TRAPS.md +1 -1
- package/src/platforms/vrp/index.ts +74 -50
- package/src/platforms/vrp/render.ts +67 -56
- package/src/project/project.ts +725 -0
- package/src/studio/app/env.d.ts +9 -0
- package/src/studio/app/index.html +18 -0
- package/src/studio/app/src/App.vue +95 -0
- package/src/studio/app/src/components/AddressesView.vue +38 -0
- package/src/studio/app/src/components/CablesView.vue +29 -0
- package/src/studio/app/src/components/CompareView.vue +160 -0
- package/src/studio/app/src/components/DataTable.vue +49 -0
- package/src/studio/app/src/components/DeviceView.vue +237 -0
- package/src/studio/app/src/components/DevicesView.vue +32 -0
- package/src/studio/app/src/components/Faceplate.vue +75 -0
- package/src/studio/app/src/components/GraphView.vue +282 -0
- package/src/studio/app/src/components/LineDiff.vue +24 -0
- package/src/studio/app/src/components/ProblemsView.vue +42 -0
- package/src/studio/app/src/components/SearchView.vue +72 -0
- package/src/studio/app/src/components/SecretsView.vue +112 -0
- package/src/studio/app/src/components/SessionsView.vue +35 -0
- package/src/studio/app/src/components/Settings.vue +95 -0
- package/src/studio/app/src/components/ToolsView.vue +118 -0
- package/src/studio/app/src/components/VlansView.vue +50 -0
- package/src/studio/app/src/lib/csv.ts +19 -0
- package/src/studio/{public/diff.js → app/src/lib/diff.ts} +40 -35
- package/src/studio/app/src/lib/format.ts +38 -0
- package/src/studio/app/src/lib/net.ts +68 -0
- package/src/studio/app/src/lib/secrets-crypto.ts +35 -0
- package/src/studio/app/src/lib/store.ts +71 -0
- package/src/studio/app/src/lib/tools.ts +217 -0
- package/src/studio/app/src/main.ts +9 -0
- package/src/studio/{public → app/src}/style.css +14 -4
- package/src/studio/app/tsconfig.json +17 -0
- package/src/studio/app/vite.config.ts +16 -0
- package/src/studio/assets.generated.ts +3 -0
- package/src/studio/data.ts +96 -188
- package/src/studio/git.ts +27 -43
- package/src/studio/server.ts +196 -107
- package/src/studio/types.ts +141 -0
- package/src/transport/console.ts +3 -3
- package/src/transport/ssh.ts +1 -1
- package/dist/chunks/index-3b343xva.js +0 -177
- package/dist/chunks/index-6wb41q67.js +0 -62
- package/dist/chunks/index-n7w3tg5y.js +0 -149
- package/dist/chunks/index-yzw86rc8.js +0 -921
- package/dist/chunks/new-w3zys5y4.js +0 -172
- package/dist/chunks/server-cxr9ynxc.js +0 -259
- package/dist/cli/index.js +0 -12922
- package/dist/helpers/index.js +0 -881
- package/dist/index.js +0 -28
- package/dist/types/core/address-space.d.ts +0 -62
- package/dist/types/core/address.d.ts +0 -44
- package/dist/types/core/cabling.d.ts +0 -41
- package/dist/types/core/cross-checks.d.ts +0 -28
- package/dist/types/core/define.d.ts +0 -79
- package/dist/types/core/project-files.d.ts +0 -12
- package/dist/types/core/schema-docs.d.ts +0 -25
- package/dist/types/core/secrets.d.ts +0 -62
- package/dist/types/core/topology.d.ts +0 -96
- package/dist/types/core/utils.d.ts +0 -10
- package/dist/types/core/validator.d.ts +0 -23
- package/dist/types/helpers/bgp.d.ts +0 -195
- package/dist/types/helpers/cables.d.ts +0 -69
- package/dist/types/helpers/checks.d.ts +0 -36
- package/dist/types/helpers/exchange.d.ts +0 -55
- package/dist/types/helpers/filters.d.ts +0 -51
- package/dist/types/helpers/index.d.ts +0 -14
- package/dist/types/helpers/route-server.d.ts +0 -52
- package/dist/types/helpers/upstreams.d.ts +0 -192
- package/dist/types/index.d.ts +0 -10
- package/dist/types/integrations/librenms.d.ts +0 -60
- package/dist/types/integrations/netbox.d.ts +0 -89
- package/dist/types/integrations/peeringdb.d.ts +0 -24
- package/dist/types/integrations/prometheus.d.ts +0 -24
- package/dist/types/integrations/registries.d.ts +0 -8
- package/dist/types/platforms/bgp-wait.d.ts +0 -24
- package/dist/types/platforms/catalog.d.ts +0 -109
- package/dist/types/platforms/derive.d.ts +0 -17
- package/dist/types/platforms/fortios/firewall.d.ts +0 -47
- package/dist/types/platforms/fortios/index.d.ts +0 -140
- package/dist/types/platforms/fortios/models.d.ts +0 -14
- package/dist/types/platforms/fortios/names.d.ts +0 -52
- package/dist/types/platforms/fortios/plan.d.ts +0 -114
- package/dist/types/platforms/fortios/render.d.ts +0 -77
- package/dist/types/platforms/fortios/routing.d.ts +0 -56
- package/dist/types/platforms/fortios/tree.d.ts +0 -37
- package/dist/types/platforms/fortios/vdoms.d.ts +0 -50
- package/dist/types/platforms/index.d.ts +0 -13
- package/dist/types/platforms/junos/bgp.d.ts +0 -44
- package/dist/types/platforms/junos/index.d.ts +0 -114
- package/dist/types/platforms/junos/models.d.ts +0 -14
- package/dist/types/platforms/junos/render.d.ts +0 -154
- package/dist/types/platforms/line-diff.d.ts +0 -67
- package/dist/types/platforms/platform.d.ts +0 -135
- package/dist/types/platforms/raisecom-ros/index.d.ts +0 -71
- package/dist/types/platforms/raisecom-ros/models.d.ts +0 -14
- package/dist/types/platforms/raisecom-ros/render.d.ts +0 -41
- package/dist/types/platforms/routeros/export.d.ts +0 -59
- package/dist/types/platforms/routeros/index.d.ts +0 -116
- package/dist/types/platforms/routeros/models.d.ts +0 -18
- package/dist/types/platforms/routeros/plan.d.ts +0 -58
- package/dist/types/platforms/routeros/render.d.ts +0 -250
- package/dist/types/platforms/vrp/index.d.ts +0 -83
- package/dist/types/platforms/vrp/models.d.ts +0 -12
- package/dist/types/platforms/vrp/render.d.ts +0 -96
- package/dist/types/schema/common.d.ts +0 -30
- package/dist/types/schema/device.d.ts +0 -126
- package/dist/types/schema/firewall.d.ts +0 -131
- package/dist/types/schema/index.d.ts +0 -8
- package/dist/types/schema/interfaces.d.ts +0 -205
- package/dist/types/schema/policy.d.ts +0 -107
- package/dist/types/schema/routing.d.ts +0 -161
- package/dist/types/schema/system.d.ts +0 -198
- package/dist/types/schema/time-zones.d.ts +0 -2
- package/dist/types/transport/console.d.ts +0 -115
- package/dist/types/transport/path-check.d.ts +0 -32
- package/dist/types/transport/ssh.d.ts +0 -27
- package/src/cli/graph-format.ts +0 -91
- package/src/cli/new.ts +0 -234
- package/src/core/address-space.ts +0 -320
- package/src/core/cross-checks.ts +0 -369
- package/src/core/define.ts +0 -124
- package/src/core/project-files.ts +0 -35
- package/src/core/schema-docs.ts +0 -174
- package/src/core/validator.ts +0 -508
- package/src/helpers/bgp.ts +0 -473
- package/src/helpers/cables.ts +0 -74
- package/src/helpers/checks.ts +0 -201
- package/src/helpers/exchange.ts +0 -123
- package/src/helpers/filters.ts +0 -107
- package/src/helpers/index.ts +0 -25
- package/src/helpers/route-server.ts +0 -212
- package/src/helpers/upstreams.ts +0 -369
- package/src/index.ts +0 -13
- package/src/integrations/librenms.ts +0 -291
- package/src/integrations/netbox.ts +0 -620
- package/src/integrations/peeringdb.ts +0 -173
- package/src/integrations/prometheus.ts +0 -90
- package/src/schema/common.ts +0 -41
- package/src/schema/device.ts +0 -145
- package/src/schema/firewall.ts +0 -140
- package/src/schema/index.ts +0 -8
- package/src/schema/policy.ts +0 -115
- package/src/schema/routing.ts +0 -173
- package/src/schema/system.ts +0 -203
- package/src/studio/public/app.js +0 -186
- package/src/studio/public/compare.js +0 -250
- package/src/studio/public/dom.js +0 -138
- package/src/studio/public/evaluate.js +0 -687
- package/src/studio/public/export.js +0 -130
- package/src/studio/public/graph.js +0 -1541
- package/src/studio/public/index.html +0 -83
- package/src/studio/public/net.js +0 -134
- package/src/studio/public/tables.js +0 -1289
- package/src/studio/public/tools.js +0 -610
- package/templates/colocation/checks.ts +0 -53
- package/templates/colocation/circuit.config.ts +0 -9
- package/templates/colocation/edge-01.ts +0 -133
- package/templates/colocation/routing.ts +0 -13
- package/templates/colocation/tenancy.ts +0 -76
- package/templates/colocation/tenants/acme.ts +0 -19
- package/templates/colocation/tenants/index.ts +0 -6
- package/templates/colocation/tor-01.ts +0 -33
- package/templates/edge-router/checks.ts +0 -20
- package/templates/edge-router/circuit.config.ts +0 -8
- package/templates/edge-router/edge-01.ts +0 -110
- package/templates/edge-router/routing.ts +0 -13
- package/templates/project/AGENTS.md +0 -51
- package/templates/project/CLAUDE.md +0 -1
- package/templates/project/README.md +0 -16
- package/templates/project/gitignore +0 -5
- package/templates/project/tsconfig.json +0 -13
- package/templates/single-site/checks.ts +0 -26
- package/templates/single-site/circuit.config.ts +0 -8
- package/templates/single-site/router.ts +0 -86
- package/templates/single-site/site.ts +0 -18
- package/templates/single-site/switch.ts +0 -34
- /package/src/studio/{public → app/public}/favicon.svg +0 -0
- /package/src/studio/{public → app/public}/special-gothic-latin-ext.woff2 +0 -0
- /package/src/studio/{public → app/public}/special-gothic-latin.woff2 +0 -0
- /package/src/studio/{public → app/public}/special-gothic-license.txt +0 -0
|
@@ -2,12 +2,9 @@
|
|
|
2
2
|
|
|
3
3
|
import { Address } from "../../core/address";
|
|
4
4
|
import { Secrets } from "../../core/secrets";
|
|
5
|
-
import type { Device, Family, Neighbor, NeighborSettings, PolicyRule } from "../../
|
|
5
|
+
import type { Device, Family, Neighbor, NeighborSettings, PolicyRule, Prefix, PrefixSet, RouteRule } from "../../model";
|
|
6
6
|
import { JunosRender, type JunosStatements } from "./render";
|
|
7
7
|
|
|
8
|
-
type AnyRule = PolicyRule<string, string>;
|
|
9
|
-
type AnyNeighbor = Neighbor<string, string, string>;
|
|
10
|
-
|
|
11
8
|
/** BGP sessions, the policies they use, prefix sets and RPKI servers, added to one device's statements. */
|
|
12
9
|
export class JunosBgp {
|
|
13
10
|
/** The policy a session uses when it states none, so that it learns or announces nothing. */
|
|
@@ -41,11 +38,23 @@ export class JunosBgp {
|
|
|
41
38
|
}
|
|
42
39
|
|
|
43
40
|
/** A neighbor's settings with its group's beneath them. */
|
|
44
|
-
static settingsOf(device: Device, neighbor:
|
|
45
|
-
const group = neighbor.
|
|
41
|
+
static settingsOf(device: Device, neighbor: Neighbor): NeighborSettings {
|
|
42
|
+
const group = neighbor.neighbor_group ? device.routing?.bgp?.neighbor_groups?.[neighbor.neighbor_group] : undefined;
|
|
46
43
|
return { ...group, ...neighbor };
|
|
47
44
|
}
|
|
48
45
|
|
|
46
|
+
/** A prefix set's prefixes, written as a list or as a map of named prefixes. A set fetched by `refresh` has none here. */
|
|
47
|
+
static prefixesOf(set: PrefixSet): Prefix[] {
|
|
48
|
+
if (!("prefixes" in set)) return [];
|
|
49
|
+
|
|
50
|
+
return Array.isArray(set.prefixes) ? [...(set.prefixes as readonly Prefix[])] : Object.values(set.prefixes);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/** A rule on routes: neither a call nor a communities rule. */
|
|
54
|
+
static isRouteRule(rule: PolicyRule): rule is RouteRule {
|
|
55
|
+
return !("call" in rule && rule.call !== undefined) && !("communities" in rule && rule.communities !== undefined);
|
|
56
|
+
}
|
|
57
|
+
|
|
49
58
|
/** A name made of a value's words, for a community or a path-length list: `64500:*` becomes `64500-any`. */
|
|
50
59
|
private static slug(value: string): string {
|
|
51
60
|
return value.replace(/\*/g, "any").replace(/[^A-Za-z0-9]+/g, "-");
|
|
@@ -57,13 +66,14 @@ export class JunosBgp {
|
|
|
57
66
|
}
|
|
58
67
|
|
|
59
68
|
/** A term's name: its place, then the rule's description so a reader sees it on the device. */
|
|
60
|
-
private static termName(label: string, rule:
|
|
69
|
+
private static termName(label: string, rule: RouteRule): string {
|
|
61
70
|
return JunosRender.quote(rule.description ? `${label} ${rule.description}` : label);
|
|
62
71
|
}
|
|
63
72
|
|
|
64
73
|
private sessions(): void {
|
|
65
74
|
const bgp = this.device.routing?.bgp;
|
|
66
|
-
|
|
75
|
+
// Without our AS there is no BGP to write; `unsupported()` names it.
|
|
76
|
+
if (!bgp || bgp.asn === undefined) return;
|
|
67
77
|
|
|
68
78
|
this.out.set("routing-options autonomous-system", bgp.asn);
|
|
69
79
|
|
|
@@ -71,35 +81,37 @@ export class JunosBgp {
|
|
|
71
81
|
let rejectAll = false;
|
|
72
82
|
let exports = false;
|
|
73
83
|
|
|
74
|
-
// One group per session: a group holds one type, internal or external, and the config's groups are only shared settings.
|
|
84
|
+
// One group per session: a group holds one type, internal or external, and the config's neighbor groups are only shared settings.
|
|
75
85
|
for (const [name, neighbor] of Object.entries(bgp.neighbors ?? {})) {
|
|
86
|
+
if (!neighbor) continue;
|
|
87
|
+
|
|
76
88
|
const settings = JunosBgp.settingsOf(this.device, neighbor);
|
|
77
89
|
const group = `protocols bgp group ${name}`;
|
|
78
90
|
|
|
79
91
|
this.out.set(group, "type", settings.remote_as === bgp.asn ? "internal" : "external");
|
|
80
92
|
this.out.set(group, "peer-as", settings.remote_as!);
|
|
81
93
|
if (settings.description) this.out.set(group, "description", JunosRender.quote(settings.description));
|
|
82
|
-
if (settings.local_address) this.out.set(group, "local-address", settings.local_address);
|
|
94
|
+
if (settings.local_address) this.out.set(group, "local-address", Address.host(settings.local_address));
|
|
83
95
|
if (settings.multihop) this.out.set(group, "multihop");
|
|
84
96
|
if (settings.passive) this.out.set(group, "passive");
|
|
85
97
|
if (settings.hold_time !== undefined) this.out.set(group, "hold-time", settings.hold_time);
|
|
86
98
|
if (settings.password) this.out.set(group, "authentication-key", Secrets.marker(settings.password));
|
|
87
99
|
if (settings.bfd) JunosRender.bfd(this.out, group, this.device);
|
|
88
100
|
|
|
89
|
-
this.out.set(group, "import", settings.
|
|
101
|
+
this.out.set(group, "import", settings.import_policy ?? JunosBgp.REJECT_ALL);
|
|
90
102
|
|
|
91
|
-
if (settings.
|
|
103
|
+
if (settings.export_policy) {
|
|
92
104
|
exports = true;
|
|
93
105
|
this.out.set(group, "export", JunosBgp.ORIGIN);
|
|
94
|
-
this.out.set(group, "export", settings.
|
|
106
|
+
this.out.set(group, "export", settings.export_policy);
|
|
95
107
|
} else this.out.set(group, "export", JunosBgp.REJECT_ALL);
|
|
96
108
|
|
|
97
|
-
for (const policy of [settings.
|
|
109
|
+
for (const policy of [settings.import_policy, settings.export_policy]) {
|
|
98
110
|
if (policy) used.add(policy);
|
|
99
111
|
else rejectAll = true;
|
|
100
112
|
}
|
|
101
113
|
|
|
102
|
-
for (const family of settings.
|
|
114
|
+
for (const family of settings.address_families ?? [Address.family(neighbor.address)]) {
|
|
103
115
|
const nlri = `${group} family ${JunosBgp.FAMILY[family]} unicast`;
|
|
104
116
|
this.out.set(nlri);
|
|
105
117
|
|
|
@@ -126,18 +138,22 @@ export class JunosBgp {
|
|
|
126
138
|
this.out.set(statement, "term bgp from protocol bgp");
|
|
127
139
|
this.out.set(statement, "term bgp then next policy");
|
|
128
140
|
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
141
|
+
// The term keeps its 0.x name, `networks`, so a device that holds it is not rewritten.
|
|
142
|
+
const originated = this.device.routing?.bgp?.originated_prefixes ?? [];
|
|
143
|
+
for (const prefix of originated) this.out.set(statement, "term networks from route-filter", prefix, "exact");
|
|
144
|
+
if (originated.length) this.out.set(statement, "term networks then next policy");
|
|
132
145
|
|
|
133
146
|
this.out.set(statement, "term others then reject");
|
|
134
147
|
}
|
|
135
148
|
|
|
136
149
|
private prefixSets(): void {
|
|
137
|
-
for (const [name, set] of Object.entries(this.device.prefix_sets ?? {})) {
|
|
150
|
+
for (const [name, set] of Object.entries(this.device.routing?.prefix_sets ?? {})) {
|
|
151
|
+
if (!set) continue;
|
|
152
|
+
|
|
138
153
|
const list = `policy-options prefix-list ${name}`;
|
|
154
|
+
const prefixes = JunosBgp.prefixesOf(set);
|
|
139
155
|
|
|
140
|
-
if (
|
|
156
|
+
if (prefixes.length) for (const prefix of prefixes) this.out.set(list, prefix);
|
|
141
157
|
else this.out.set(list);
|
|
142
158
|
|
|
143
159
|
if ("source" in set) this.out.note(`${JunosBgp.GENERATED}${list}`);
|
|
@@ -151,31 +167,33 @@ export class JunosBgp {
|
|
|
151
167
|
}
|
|
152
168
|
|
|
153
169
|
/** The family a rule is limited to, by its match: a family, a prefix, or a prefix set of one family. */
|
|
154
|
-
private familyOfRule(rule:
|
|
155
|
-
const match = rule.
|
|
170
|
+
private familyOfRule(rule: RouteRule): Family | undefined {
|
|
171
|
+
const match = rule.if;
|
|
156
172
|
if (match?.family) return match.family;
|
|
157
173
|
|
|
158
174
|
if (match?.prefix) return Address.family(Address.host(match.prefix));
|
|
159
175
|
|
|
160
|
-
const set = match?.prefix_set ? this.device.prefix_sets?.[match.prefix_set] : undefined;
|
|
176
|
+
const set = match?.prefix_set ? this.device.routing?.prefix_sets?.[match.prefix_set] : undefined;
|
|
161
177
|
if (set && "source" in set) return set.source.family;
|
|
162
178
|
|
|
163
|
-
|
|
179
|
+
const first = set && JunosBgp.prefixesOf(set)[0];
|
|
180
|
+
if (first) return Address.family(Address.host(first));
|
|
164
181
|
|
|
165
182
|
return undefined;
|
|
166
183
|
}
|
|
167
184
|
|
|
168
185
|
/** A policy's rules with each call replaced by the rules it calls, in order. A called policy that decides nothing hands back to the caller, as it does on every platform. */
|
|
169
|
-
private flatten(policy: string, label: string, seen: string[]): { label: string; rule:
|
|
170
|
-
const rules = this.device.policies?.[policy] ?? [];
|
|
171
|
-
const flat: { label: string; rule:
|
|
186
|
+
private flatten(policy: string, label: string, seen: string[]): { label: string; rule: RouteRule }[] {
|
|
187
|
+
const rules = this.device.routing?.policies?.[policy] ?? [];
|
|
188
|
+
const flat: { label: string; rule: RouteRule }[] = [];
|
|
172
189
|
|
|
173
190
|
rules.forEach((rule, index) => {
|
|
174
191
|
const here = label ? `${label}.${index + 1}` : `${index + 1}`;
|
|
175
192
|
|
|
176
|
-
if (rule.call && !seen.includes(rule.call)) flat.push(...this.flatten(rule.call, here, [...seen, rule.call]));
|
|
193
|
+
if ("call" in rule && rule.call && !seen.includes(rule.call)) flat.push(...this.flatten(rule.call, here, [...seen, rule.call]));
|
|
177
194
|
|
|
178
|
-
|
|
195
|
+
// A communities rule is not written here; `unsupported()` names it.
|
|
196
|
+
if (JunosBgp.isRouteRule(rule) && (rule.if || rule.set || rule.then)) flat.push({ label: here, rule });
|
|
179
197
|
});
|
|
180
198
|
|
|
181
199
|
return flat;
|
|
@@ -189,7 +207,7 @@ export class JunosBgp {
|
|
|
189
207
|
for (const { label, rule } of flat) {
|
|
190
208
|
const family = this.familyOfRule(rule);
|
|
191
209
|
// A next hop only means something to routes of its own family, and one term cannot filter prefixes of both, so a rule for both families splits into a term for each.
|
|
192
|
-
const split = !family && (rule.set?.next_hop || rule.
|
|
210
|
+
const split = !family && (rule.set?.next_hop || rule.if?.prefix_length) ? (["ipv4", "ipv6"] as const) : [family];
|
|
193
211
|
|
|
194
212
|
for (const part of split) {
|
|
195
213
|
const name =
|
|
@@ -201,12 +219,12 @@ export class JunosBgp {
|
|
|
201
219
|
}
|
|
202
220
|
|
|
203
221
|
const last = flat.at(-1)?.rule;
|
|
204
|
-
const decides = last !== undefined && !last.
|
|
222
|
+
const decides = last !== undefined && !last.if && last.then !== undefined;
|
|
205
223
|
if (!decides) this.out.set(statement, "term circuit-default then reject");
|
|
206
224
|
}
|
|
207
225
|
|
|
208
|
-
private term(term: string, rule:
|
|
209
|
-
const match = rule.
|
|
226
|
+
private term(term: string, rule: RouteRule, family: Family | undefined, splitFamily: boolean): void {
|
|
227
|
+
const match = rule.if ?? {};
|
|
210
228
|
const set = rule.set ?? {};
|
|
211
229
|
const from: (string | number)[][] = [];
|
|
212
230
|
const then: (string | number)[][] = [];
|
|
@@ -232,9 +250,9 @@ export class JunosBgp {
|
|
|
232
250
|
from.push(["as-path", name]);
|
|
233
251
|
}
|
|
234
252
|
|
|
235
|
-
if (match.
|
|
236
|
-
const name = `circuit-through-${match.
|
|
237
|
-
this.out.set(`policy-options as-path ${name}`, JunosRender.quote(`.* ${match.
|
|
253
|
+
if (match.as_path_contains !== undefined) {
|
|
254
|
+
const name = `circuit-through-${match.as_path_contains}`;
|
|
255
|
+
this.out.set(`policy-options as-path ${name}`, JunosRender.quote(`.* ${match.as_path_contains} .*`));
|
|
238
256
|
from.push(["as-path", name]);
|
|
239
257
|
}
|
|
240
258
|
|
|
@@ -242,7 +260,7 @@ export class JunosBgp {
|
|
|
242
260
|
|
|
243
261
|
// Members of one named community must all be present, so a rule matching both kinds names them together.
|
|
244
262
|
const wanted = [
|
|
245
|
-
...(match.
|
|
263
|
+
...(match.standard_community ? [JunosBgp.member(match.standard_community, false)] : []),
|
|
246
264
|
...(match.large_community ? [JunosBgp.member(match.large_community, true)] : []),
|
|
247
265
|
];
|
|
248
266
|
|
|
@@ -252,22 +270,25 @@ export class JunosBgp {
|
|
|
252
270
|
if (set.med !== undefined) then.push(["metric", set.med]);
|
|
253
271
|
|
|
254
272
|
if (set.prepend !== undefined) {
|
|
255
|
-
const asn = this.device.routing!.bgp!.asn
|
|
273
|
+
const asn = this.device.routing!.bgp!.asn!;
|
|
256
274
|
then.push(["as-path-prepend", JunosRender.quote(Array(set.prepend).fill(asn).join(" "))]);
|
|
257
275
|
}
|
|
258
276
|
|
|
259
277
|
// Replacing communities of one kind is removing every one of that kind, then adding the new ones.
|
|
260
278
|
const removed = [
|
|
261
|
-
...(set.
|
|
279
|
+
...(set.standard_communities ? ["*:*"] : (set.remove_standard_communities ?? [])).map((pattern) =>
|
|
280
|
+
JunosBgp.member(pattern, false)
|
|
281
|
+
),
|
|
262
282
|
...(set.large_communities ? ["*:*:*"] : (set.remove_large_communities ?? [])).map((pattern) => JunosBgp.member(pattern, true)),
|
|
263
283
|
];
|
|
264
284
|
|
|
265
285
|
const added = [
|
|
266
|
-
...(set.
|
|
286
|
+
...(set.standard_communities ?? set.add_standard_communities ?? []).map((value) => JunosBgp.member(value, false)),
|
|
267
287
|
...(set.large_communities ?? set.add_large_communities ?? []).map((value) => JunosBgp.member(value, true)),
|
|
268
288
|
];
|
|
269
289
|
|
|
270
|
-
if (set.
|
|
290
|
+
if (set.standard_communities && set.add_standard_communities)
|
|
291
|
+
added.push(...set.add_standard_communities.map((value) => JunosBgp.member(value, false)));
|
|
271
292
|
if (set.large_communities && set.add_large_communities)
|
|
272
293
|
added.push(...set.add_large_communities.map((value) => JunosBgp.member(value, true)));
|
|
273
294
|
|
|
@@ -276,7 +297,7 @@ export class JunosBgp {
|
|
|
276
297
|
|
|
277
298
|
if (set.next_hop && (!family || Address.family(set.next_hop) === family)) then.push(["next-hop", set.next_hop]);
|
|
278
299
|
if (set.blackhole) then.push(["next-hop discard"]);
|
|
279
|
-
if (rule.
|
|
300
|
+
if (rule.then) then.push([rule.then]);
|
|
280
301
|
|
|
281
302
|
for (const words of from) this.out.set(term, "from", ...words);
|
|
282
303
|
for (const words of then) this.out.set(term, "then", ...words);
|