1{ config, lib, pkgs, ... }:
2
3with lib;
4with import ./systemd-unit-options.nix { inherit config lib; };
5with import ./systemd-lib.nix { inherit config lib pkgs; };
6
7let
8
9 cfg = config.systemd.network;
10
11 checkLink = checkUnitConfig "Link" [
12 (assertOnlyFields [
13 "Description" "Alias" "MACAddressPolicy" "MACAddress" "NamePolicy" "Name"
14 "MTUBytes" "BitsPerSecond" "Duplex" "WakeOnLan"
15 ])
16 (assertValueOneOf "MACAddressPolicy" ["persistent" "random"])
17 (assertMacAddress "MACAddress")
18 (assertValueOneOf "NamePolicy" [
19 "kernel" "database" "onboard" "slot" "path" "mac"
20 ])
21 (assertByteFormat "MTUBytes")
22 (assertByteFormat "BitsPerSecond")
23 (assertValueOneOf "Duplex" ["half" "full"])
24 (assertValueOneOf "WakeOnLan" ["phy" "magic" "off"])
25 ];
26
27 checkNetdev = checkUnitConfig "Netdev" [
28 (assertOnlyFields [
29 "Description" "Name" "Kind" "MTUBytes" "MACAddress"
30 ])
31 (assertHasField "Name")
32 (assertHasField "Kind")
33 (assertValueOneOf "Kind" [
34 "bridge" "bond" "vlan" "macvlan" "vxlan" "ipip"
35 "gre" "sit" "vti" "veth" "tun" "tap" "dummy"
36 ])
37 (assertByteFormat "MTUBytes")
38 (assertMacAddress "MACAddress")
39 ];
40
41 checkVlan = checkUnitConfig "VLAN" [
42 (assertOnlyFields ["Id"])
43 (assertRange "Id" 0 4094)
44 ];
45
46 checkMacvlan = checkUnitConfig "MACVLAN" [
47 (assertOnlyFields ["Mode"])
48 (assertValueOneOf "Mode" ["private" "vepa" "bridge" "passthru"])
49 ];
50
51 checkVxlan = checkUnitConfig "VXLAN" [
52 (assertOnlyFields ["Id" "Group" "TOS" "TTL" "MacLearning"])
53 (assertRange "TTL" 0 255)
54 (assertValueOneOf "MacLearning" boolValues)
55 ];
56
57 checkTunnel = checkUnitConfig "Tunnel" [
58 (assertOnlyFields ["Local" "Remote" "TOS" "TTL" "DiscoverPathMTU"])
59 (assertRange "TTL" 0 255)
60 (assertValueOneOf "DiscoverPathMTU" boolValues)
61 ];
62
63 checkPeer = checkUnitConfig "Peer" [
64 (assertOnlyFields ["Name" "MACAddress"])
65 (assertMacAddress "MACAddress")
66 ];
67
68 tunTapChecks = [
69 (assertOnlyFields ["OneQueue" "MultiQueue" "PacketInfo" "User" "Group"])
70 (assertValueOneOf "OneQueue" boolValues)
71 (assertValueOneOf "MultiQueue" boolValues)
72 (assertValueOneOf "PacketInfo" boolValues)
73 ];
74
75 checkTun = checkUnitConfig "Tun" tunTapChecks;
76
77 checkTap = checkUnitConfig "Tap" tunTapChecks;
78
79 checkBond = checkUnitConfig "Bond" [
80 (assertOnlyFields [
81 "Mode" "TransmitHashPolicy" "LACPTransmitRate" "MIIMonitorSec"
82 "UpDelaySec" "DownDelaySec"
83 ])
84 (assertValueOneOf "Mode" [
85 "balance-rr" "active-backup" "balance-xor"
86 "broadcast" "802.3ad" "balance-tlb" "balance-alb"
87 ])
88 (assertValueOneOf "TransmitHashPolicy" [
89 "layer2" "layer3+4" "layer2+3" "encap2+3" "802.3ad" "encap3+4"
90 ])
91 (assertValueOneOf "LACPTransmitRate" ["slow" "fast"])
92 ];
93
94 checkNetwork = checkUnitConfig "Network" [
95 (assertOnlyFields [
96 "Description" "DHCP" "DHCPServer" "IPForward" "IPMasquerade" "IPv4LL" "IPv4LLRoute"
97 "LLMNR" "Domains" "Bridge" "Bond"
98 ])
99 (assertValueOneOf "DHCP" ["both" "none" "v4" "v6"])
100 (assertValueOneOf "DHCPServer" boolValues)
101 (assertValueOneOf "IPForward" ["yes" "no" "ipv4" "ipv6"])
102 (assertValueOneOf "IPMasquerade" boolValues)
103 (assertValueOneOf "IPv4LL" boolValues)
104 (assertValueOneOf "IPv4LLRoute" boolValues)
105 (assertValueOneOf "LLMNR" boolValues)
106 ];
107
108 checkAddress = checkUnitConfig "Address" [
109 (assertOnlyFields ["Address" "Peer" "Broadcast" "Label"])
110 (assertHasField "Address")
111 ];
112
113 checkRoute = checkUnitConfig "Route" [
114 (assertOnlyFields ["Gateway" "Destination" "Metric"])
115 (assertHasField "Gateway")
116 ];
117
118 checkDhcp = checkUnitConfig "DHCP" [
119 (assertOnlyFields [
120 "UseDNS" "UseMTU" "SendHostname" "UseHostname" "UseDomains" "UseRoutes"
121 "CriticalConnections" "VendorClassIdentifier" "RequestBroadcast"
122 "RouteMetric"
123 ])
124 (assertValueOneOf "UseDNS" boolValues)
125 (assertValueOneOf "UseMTU" boolValues)
126 (assertValueOneOf "SendHostname" boolValues)
127 (assertValueOneOf "UseHostname" boolValues)
128 (assertValueOneOf "UseDomains" boolValues)
129 (assertValueOneOf "UseRoutes" boolValues)
130 (assertValueOneOf "CriticalConnections" boolValues)
131 (assertValueOneOf "RequestBroadcast" boolValues)
132 ];
133
134 checkDhcpServer = checkUnitConfig "DHCPServer" [
135 (assertOnlyFields [
136 "PoolOffset" "PoolSize" "DefaultLeaseTimeSec" "MaxLeaseTimeSec"
137 "EmitDNS" "DNS" "EmitNTP" "NTP" "EmitTimezone" "Timezone"
138 ])
139 (assertValueOneOf "EmitDNS" boolValues)
140 (assertValueOneOf "EmitNTP" boolValues)
141 (assertValueOneOf "EmitTimezone" boolValues)
142 ];
143
144 commonNetworkOptions = {
145
146 enable = mkOption {
147 default = true;
148 type = types.bool;
149 description = ''
150 Whether to manage network configuration using <command>systemd-network</command>.
151 '';
152 };
153
154 matchConfig = mkOption {
155 default = {};
156 example = { Name = "eth0"; };
157 type = types.attrsOf unitOption;
158 description = ''
159 Each attribute in this set specifies an option in the
160 <literal>[Match]</literal> section of the unit. See
161 <citerefentry><refentrytitle>systemd.link</refentrytitle><manvolnum>5</manvolnum></citerefentry>
162 <citerefentry><refentrytitle>systemd.netdev</refentrytitle><manvolnum>5</manvolnum></citerefentry>
163 <citerefentry><refentrytitle>systemd.network</refentrytitle><manvolnum>5</manvolnum></citerefentry>
164 for details.
165 '';
166 };
167
168 };
169
170 linkOptions = commonNetworkOptions // {
171
172 linkConfig = mkOption {
173 default = {};
174 example = { MACAddress = "00:ff:ee:aa:cc:dd"; };
175 type = types.addCheck (types.attrsOf unitOption) checkLink;
176 description = ''
177 Each attribute in this set specifies an option in the
178 <literal>[Link]</literal> section of the unit. See
179 <citerefentry><refentrytitle>systemd.link</refentrytitle>
180 <manvolnum>5</manvolnum></citerefentry> for details.
181 '';
182 };
183
184 };
185
186 netdevOptions = commonNetworkOptions // {
187
188 netdevConfig = mkOption {
189 default = {};
190 example = { Name = "mybridge"; Kind = "bridge"; };
191 type = types.addCheck (types.attrsOf unitOption) checkNetdev;
192 description = ''
193 Each attribute in this set specifies an option in the
194 <literal>[Netdev]</literal> section of the unit. See
195 <citerefentry><refentrytitle>systemd.netdev</refentrytitle>
196 <manvolnum>5</manvolnum></citerefentry> for details.
197 '';
198 };
199
200 vlanConfig = mkOption {
201 default = {};
202 example = { Id = "4"; };
203 type = types.addCheck (types.attrsOf unitOption) checkVlan;
204 description = ''
205 Each attribute in this set specifies an option in the
206 <literal>[VLAN]</literal> section of the unit. See
207 <citerefentry><refentrytitle>systemd.netdev</refentrytitle>
208 <manvolnum>5</manvolnum></citerefentry> for details.
209 '';
210 };
211
212 macvlanConfig = mkOption {
213 default = {};
214 example = { Mode = "private"; };
215 type = types.addCheck (types.attrsOf unitOption) checkMacvlan;
216 description = ''
217 Each attribute in this set specifies an option in the
218 <literal>[MACVLAN]</literal> section of the unit. See
219 <citerefentry><refentrytitle>systemd.netdev</refentrytitle>
220 <manvolnum>5</manvolnum></citerefentry> for details.
221 '';
222 };
223
224 vxlanConfig = mkOption {
225 default = {};
226 example = { Id = "4"; };
227 type = types.addCheck (types.attrsOf unitOption) checkVxlan;
228 description = ''
229 Each attribute in this set specifies an option in the
230 <literal>[VXLAN]</literal> section of the unit. See
231 <citerefentry><refentrytitle>systemd.netdev</refentrytitle>
232 <manvolnum>5</manvolnum></citerefentry> for details.
233 '';
234 };
235
236 tunnelConfig = mkOption {
237 default = {};
238 example = { Remote = "192.168.1.1"; };
239 type = types.addCheck (types.attrsOf unitOption) checkTunnel;
240 description = ''
241 Each attribute in this set specifies an option in the
242 <literal>[Tunnel]</literal> section of the unit. See
243 <citerefentry><refentrytitle>systemd.netdev</refentrytitle>
244 <manvolnum>5</manvolnum></citerefentry> for details.
245 '';
246 };
247
248 peerConfig = mkOption {
249 default = {};
250 example = { Name = "veth2"; };
251 type = types.addCheck (types.attrsOf unitOption) checkPeer;
252 description = ''
253 Each attribute in this set specifies an option in the
254 <literal>[Peer]</literal> section of the unit. See
255 <citerefentry><refentrytitle>systemd.netdev</refentrytitle>
256 <manvolnum>5</manvolnum></citerefentry> for details.
257 '';
258 };
259
260 tunConfig = mkOption {
261 default = {};
262 example = { User = "openvpn"; };
263 type = types.addCheck (types.attrsOf unitOption) checkTun;
264 description = ''
265 Each attribute in this set specifies an option in the
266 <literal>[Tun]</literal> section of the unit. See
267 <citerefentry><refentrytitle>systemd.netdev</refentrytitle>
268 <manvolnum>5</manvolnum></citerefentry> for details.
269 '';
270 };
271
272 tapConfig = mkOption {
273 default = {};
274 example = { User = "openvpn"; };
275 type = types.addCheck (types.attrsOf unitOption) checkTap;
276 description = ''
277 Each attribute in this set specifies an option in the
278 <literal>[Tap]</literal> section of the unit. See
279 <citerefentry><refentrytitle>systemd.netdev</refentrytitle>
280 <manvolnum>5</manvolnum></citerefentry> for details.
281 '';
282 };
283
284 bondConfig = mkOption {
285 default = {};
286 example = { Mode = "802.3ad"; };
287 type = types.addCheck (types.attrsOf unitOption) checkBond;
288 description = ''
289 Each attribute in this set specifies an option in the
290 <literal>[Bond]</literal> section of the unit. See
291 <citerefentry><refentrytitle>systemd.netdev</refentrytitle>
292 <manvolnum>5</manvolnum></citerefentry> for details.
293 '';
294 };
295
296 };
297
298 addressOptions = {
299
300 addressConfig = mkOption {
301 default = {};
302 example = { Address = "192.168.0.100/24"; };
303 type = types.addCheck (types.attrsOf unitOption) checkAddress;
304 description = ''
305 Each attribute in this set specifies an option in the
306 <literal>[Address]</literal> section of the unit. See
307 <citerefentry><refentrytitle>systemd.network</refentrytitle>
308 <manvolnum>5</manvolnum></citerefentry> for details.
309 '';
310 };
311
312 };
313
314 routeOptions = {
315
316 routeConfig = mkOption {
317 default = {};
318 example = { Gateway = "192.168.0.1"; };
319 type = types.addCheck (types.attrsOf unitOption) checkRoute;
320 description = ''
321 Each attribute in this set specifies an option in the
322 <literal>[Route]</literal> section of the unit. See
323 <citerefentry><refentrytitle>systemd.network</refentrytitle>
324 <manvolnum>5</manvolnum></citerefentry> for details.
325 '';
326 };
327
328 };
329
330 networkOptions = commonNetworkOptions // {
331
332 networkConfig = mkOption {
333 default = {};
334 example = { Description = "My Network"; };
335 type = types.addCheck (types.attrsOf unitOption) checkNetwork;
336 description = ''
337 Each attribute in this set specifies an option in the
338 <literal>[Network]</literal> section of the unit. See
339 <citerefentry><refentrytitle>systemd.network</refentrytitle>
340 <manvolnum>5</manvolnum></citerefentry> for details.
341 '';
342 };
343
344 dhcpConfig = mkOption {
345 default = {};
346 example = { UseDNS = true; UseRoutes = true; };
347 type = types.addCheck (types.attrsOf unitOption) checkDhcp;
348 description = ''
349 Each attribute in this set specifies an option in the
350 <literal>[DHCP]</literal> section of the unit. See
351 <citerefentry><refentrytitle>systemd.network</refentrytitle>
352 <manvolnum>5</manvolnum></citerefentry> for details.
353 '';
354 };
355
356 dhcpServerConfig = mkOption {
357 default = {};
358 example = { PoolOffset = 50; EmitDNS = false; };
359 type = types.addCheck (types.attrsOf unitOption) checkDhcpServer;
360 description = ''
361 Each attribute in this set specifies an option in the
362 <literal>[DHCPServer]</literal> section of the unit. See
363 <citerefentry><refentrytitle>systemd.network</refentrytitle>
364 <manvolnum>5</manvolnum></citerefentry> for details.
365 '';
366 };
367
368 name = mkOption {
369 type = types.nullOr types.str;
370 default = null;
371 description = ''
372 The name of the network interface to match against.
373 '';
374 };
375
376 DHCP = mkOption {
377 type = types.nullOr types.str;
378 default = null;
379 description = ''
380 Whether to enable DHCP on the interfaces matched.
381 '';
382 };
383
384 domains = mkOption {
385 type = types.nullOr (types.listOf types.str);
386 default = null;
387 description = ''
388 A list of domains to pass to the network config.
389 '';
390 };
391
392 address = mkOption {
393 default = [ ];
394 type = types.listOf types.str;
395 description = ''
396 A list of addresses to be added to the network section of the
397 unit. See <citerefentry><refentrytitle>systemd.network</refentrytitle>
398 <manvolnum>5</manvolnum></citerefentry> for details.
399 '';
400 };
401
402 gateway = mkOption {
403 default = [ ];
404 type = types.listOf types.str;
405 description = ''
406 A list of gateways to be added to the network section of the
407 unit. See <citerefentry><refentrytitle>systemd.network</refentrytitle>
408 <manvolnum>5</manvolnum></citerefentry> for details.
409 '';
410 };
411
412 dns = mkOption {
413 default = [ ];
414 type = types.listOf types.str;
415 description = ''
416 A list of dns servers to be added to the network section of the
417 unit. See <citerefentry><refentrytitle>systemd.network</refentrytitle>
418 <manvolnum>5</manvolnum></citerefentry> for details.
419 '';
420 };
421
422 ntp = mkOption {
423 default = [ ];
424 type = types.listOf types.str;
425 description = ''
426 A list of ntp servers to be added to the network section of the
427 unit. See <citerefentry><refentrytitle>systemd.network</refentrytitle>
428 <manvolnum>5</manvolnum></citerefentry> for details.
429 '';
430 };
431
432 vlan = mkOption {
433 default = [ ];
434 type = types.listOf types.str;
435 description = ''
436 A list of vlan interfaces to be added to the network section of the
437 unit. See <citerefentry><refentrytitle>systemd.network</refentrytitle>
438 <manvolnum>5</manvolnum></citerefentry> for details.
439 '';
440 };
441
442 macvlan = mkOption {
443 default = [ ];
444 type = types.listOf types.str;
445 description = ''
446 A list of macvlan interfaces to be added to the network section of the
447 unit. See <citerefentry><refentrytitle>systemd.network</refentrytitle>
448 <manvolnum>5</manvolnum></citerefentry> for details.
449 '';
450 };
451
452 vxlan = mkOption {
453 default = [ ];
454 type = types.listOf types.str;
455 description = ''
456 A list of vxlan interfaces to be added to the network section of the
457 unit. See <citerefentry><refentrytitle>systemd.network</refentrytitle>
458 <manvolnum>5</manvolnum></citerefentry> for details.
459 '';
460 };
461
462 tunnel = mkOption {
463 default = [ ];
464 type = types.listOf types.str;
465 description = ''
466 A list of tunnel interfaces to be added to the network section of the
467 unit. See <citerefentry><refentrytitle>systemd.network</refentrytitle>
468 <manvolnum>5</manvolnum></citerefentry> for details.
469 '';
470 };
471
472 addresses = mkOption {
473 default = [ ];
474 type = types.listOf types.optionSet;
475 options = [ addressOptions ];
476 description = ''
477 A list of address sections to be added to the unit. See
478 <citerefentry><refentrytitle>systemd.network</refentrytitle>
479 <manvolnum>5</manvolnum></citerefentry> for details.
480 '';
481 };
482
483 routes = mkOption {
484 default = [ ];
485 type = types.listOf types.optionSet;
486 options = [ routeOptions ];
487 description = ''
488 A list of route sections to be added to the unit. See
489 <citerefentry><refentrytitle>systemd.network</refentrytitle>
490 <manvolnum>5</manvolnum></citerefentry> for details.
491 '';
492 };
493
494 };
495
496 networkConfig = { name, config, ... }: {
497 config = {
498 matchConfig = optionalAttrs (config.name != null) {
499 Name = config.name;
500 };
501 networkConfig = optionalAttrs (config.DHCP != null) {
502 DHCP = config.DHCP;
503 } // optionalAttrs (config.domains != null) {
504 Domains = concatStringsSep " " config.domains;
505 };
506 };
507 };
508
509 commonMatchText = def: ''
510 [Match]
511 ${attrsToSection def.matchConfig}
512 '';
513
514 linkToUnit = name: def:
515 { inherit (def) enable;
516 text = commonMatchText def +
517 ''
518 [Link]
519 ${attrsToSection def.linkConfig}
520 '';
521 };
522
523 netdevToUnit = name: def:
524 { inherit (def) enable;
525 text = commonMatchText def +
526 ''
527 [NetDev]
528 ${attrsToSection def.netdevConfig}
529
530 ${optionalString (def.vlanConfig != { }) ''
531 [VLAN]
532 ${attrsToSection def.vlanConfig}
533
534 ''}
535 ${optionalString (def.macvlanConfig != { }) ''
536 [MACVLAN]
537 ${attrsToSection def.macvlanConfig}
538
539 ''}
540 ${optionalString (def.vxlanConfig != { }) ''
541 [VXLAN]
542 ${attrsToSection def.vxlanConfig}
543
544 ''}
545 ${optionalString (def.tunnelConfig != { }) ''
546 [Tunnel]
547 ${attrsToSection def.tunnelConfig}
548
549 ''}
550 ${optionalString (def.peerConfig != { }) ''
551 [Peer]
552 ${attrsToSection def.peerConfig}
553
554 ''}
555 ${optionalString (def.tunConfig != { }) ''
556 [Tun]
557 ${attrsToSection def.tunConfig}
558
559 ''}
560 ${optionalString (def.tapConfig != { }) ''
561 [Tap]
562 ${attrsToSection def.tapConfig}
563
564 ''}
565 ${optionalString (def.bondConfig != { }) ''
566 [Bond]
567 ${attrsToSection def.bondConfig}
568
569 ''}
570 '';
571 };
572
573 networkToUnit = name: def:
574 { inherit (def) enable;
575 text = commonMatchText def +
576 ''
577 [Network]
578 ${attrsToSection def.networkConfig}
579 ${concatStringsSep "\n" (map (s: "Address=${s}") def.address)}
580 ${concatStringsSep "\n" (map (s: "Gateway=${s}") def.gateway)}
581 ${concatStringsSep "\n" (map (s: "DNS=${s}") def.dns)}
582 ${concatStringsSep "\n" (map (s: "NTP=${s}") def.ntp)}
583 ${concatStringsSep "\n" (map (s: "VLAN=${s}") def.vlan)}
584 ${concatStringsSep "\n" (map (s: "MACVLAN=${s}") def.macvlan)}
585 ${concatStringsSep "\n" (map (s: "VXLAN=${s}") def.vxlan)}
586 ${concatStringsSep "\n" (map (s: "Tunnel=${s}") def.tunnel)}
587
588 ${optionalString (def.dhcpConfig != { }) ''
589 [DHCP]
590 ${attrsToSection def.dhcpConfig}
591
592 ''}
593 ${optionalString (def.dhcpServerConfig != { }) ''
594 [DHCPServer]
595 ${attrsToSection def.dhcpServerConfig}
596
597 ''}
598 ${flip concatMapStrings def.addresses (x: ''
599 [Address]
600 ${attrsToSection x.addressConfig}
601
602 '')}
603 ${flip concatMapStrings def.routes (x: ''
604 [Route]
605 ${attrsToSection x.routeConfig}
606
607 '')}
608 '';
609 };
610
611in
612
613{
614
615 options = {
616
617 systemd.network.enable = mkOption {
618 default = false;
619 type = types.bool;
620 description = ''
621 Whether to enable networkd or not.
622 '';
623 };
624
625 systemd.network.links = mkOption {
626 default = {};
627 type = types.attrsOf types.optionSet;
628 options = [ linkOptions ];
629 description = "Definition of systemd network links.";
630 };
631
632 systemd.network.netdevs = mkOption {
633 default = {};
634 type = types.attrsOf types.optionSet;
635 options = [ netdevOptions ];
636 description = "Definition of systemd network devices.";
637 };
638
639 systemd.network.networks = mkOption {
640 default = {};
641 type = types.attrsOf types.optionSet;
642 options = [ networkOptions networkConfig ];
643 description = "Definition of systemd networks.";
644 };
645
646 systemd.network.units = mkOption {
647 description = "Definition of networkd units.";
648 default = {};
649 type = types.attrsOf types.optionSet;
650 options = { name, config, ... }:
651 { options = concreteUnitOptions;
652 config = {
653 unit = mkDefault (makeUnit name config);
654 };
655 };
656 };
657
658 };
659
660 config = mkIf config.systemd.network.enable {
661
662 systemd.additionalUpstreamSystemUnits =
663 [ "systemd-networkd.service" "systemd-networkd-wait-online.service" ];
664
665 systemd.network.units =
666 mapAttrs' (n: v: nameValuePair "${n}.link" (linkToUnit n v)) cfg.links
667 // mapAttrs' (n: v: nameValuePair "${n}.netdev" (netdevToUnit n v)) cfg.netdevs
668 // mapAttrs' (n: v: nameValuePair "${n}.network" (networkToUnit n v)) cfg.networks;
669
670 environment.etc."systemd/network".source =
671 generateUnits "network" cfg.units [] [];
672
673 systemd.services.systemd-networkd = {
674 wantedBy = [ "multi-user.target" ];
675 before = [ "network-interfaces.target" ];
676 restartTriggers = [ config.environment.etc."systemd/network".source ];
677 };
678
679 systemd.services.systemd-networkd-wait-online = {
680 before = [ "network-online.target" "ip-up.target" ];
681 wantedBy = [ "network-online.target" "ip-up.target" ];
682 };
683
684 systemd.services."systemd-network-wait-online@" = {
685 description = "Wait for Network Interface %I to be Configured";
686 conflicts = [ "shutdown.target" ];
687 requisite = [ "systemd-networkd.service" ];
688 after = [ "systemd-networkd.service" ];
689 serviceConfig = {
690 Type = "oneshot";
691 RemainAfterExit = true;
692 ExecStart = "${config.systemd.package}/lib/systemd/systemd-networkd-wait-online -i %I";
693 };
694 };
695
696 services.resolved.enable = mkDefault true;
697 services.timesyncd.enable = mkDefault config.services.ntp.enable;
698
699 };
700
701}