Skip to content

Commit 360c662

Browse files
SJrXSteve Ramageclaude
authored
feat: give [Route] directives their correct grammars (config_parse_route_section) (#493)
Every config_parse_route_section ltype mapped to the generic ConfigParseRouteSectionOptionValue, so most [Route] directives in .network files got no real validation. Point each ltype at a validator matching its systemd semantics, and add the two gateway ltypes that had no entry: ROUTE_GATEWAY -> IPv4/IPv6 address, or _dhcp4 / _ipv6ra ROUTE_GATEWAY_NETWORK -> gateway-or-network form ROUTE_METRIC_*COOKIE / *QUICKACK -> boolean ROUTE_METRIC_HOPLIMIT -> hop limit ROUTE_METRIC_INITRWND -> initial window ROUTE_NEXTHOP/PRIORITY -> uint32 ROUTE_PREFERENCE -> low|medium|high ROUTE_PROTOCOL -> protocol enum (ROUTE_TYPE stays on the generic validator) Bundles the route_section work from the stacked PRs #475 (Gateway=) and #486 (the remaining ltypes); both edit the same registry block, so they ship as one cohesive MR re-cut against current 242.x. Default-path fix (both engines). Co-authored-by: Steve Ramage <gitcommits@sjrx.net> Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
1 parent 4aa8fa0 commit 360c662

11 files changed

Lines changed: 247 additions & 8 deletions

src/main/kotlin/net/sjrx/intellij/plugins/systemdunitfiles/semanticdata/optionvalues/AiGenerated.kt

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -189,14 +189,16 @@ fun getAllAIGeneratedValidators(): Map<Validator, OptionValueInformation> {
189189
Validator("config_parse_restrict_network_interfaces", "0") to ConfigParseRestrictNetworkInterfacesOptionValue() as OptionValueInformation,
190190
Validator("config_parse_ring_buffer_or_channel", "0") to ConfigParseRingBufferOrChannelOptionValue() as OptionValueInformation,
191191
Validator("config_parse_route_prefix_preference", "0") to ConfigParseRoutePrefixPreferenceOptionValue() as OptionValueInformation,
192-
Validator("config_parse_route_section", "ROUTE_METRIC_FASTOPEN_NO_COOKIE") to ConfigParseRouteSectionOptionValue() as OptionValueInformation,
193-
Validator("config_parse_route_section", "ROUTE_METRIC_HOPLIMIT") to ConfigParseRouteSectionOptionValue() as OptionValueInformation,
194-
Validator("config_parse_route_section", "ROUTE_METRIC_INITRWND") to ConfigParseRouteSectionOptionValue() as OptionValueInformation,
195-
Validator("config_parse_route_section", "ROUTE_METRIC_QUICKACK") to ConfigParseRouteSectionOptionValue() as OptionValueInformation,
196-
Validator("config_parse_route_section", "ROUTE_NEXTHOP") to ConfigParseRouteSectionOptionValue() as OptionValueInformation,
197-
Validator("config_parse_route_section", "ROUTE_PREFERENCE") to ConfigParseRouteSectionOptionValue() as OptionValueInformation,
198-
Validator("config_parse_route_section", "ROUTE_PRIORITY") to ConfigParseRouteSectionOptionValue() as OptionValueInformation,
199-
Validator("config_parse_route_section", "ROUTE_PROTOCOL") to ConfigParseRouteSectionOptionValue() as OptionValueInformation,
192+
Validator("config_parse_route_section", "ROUTE_GATEWAY") to ConfigParseRouteSectionGatewayOptionValue() as OptionValueInformation,
193+
Validator("config_parse_route_section", "ROUTE_GATEWAY_NETWORK") to ConfigParseRouteSectionGatewayNetworkOptionValue() as OptionValueInformation,
194+
Validator("config_parse_route_section", "ROUTE_METRIC_FASTOPEN_NO_COOKIE") to ConfigParseRouteSectionBooleanOptionValue() as OptionValueInformation,
195+
Validator("config_parse_route_section", "ROUTE_METRIC_HOPLIMIT") to ConfigParseRouteSectionHopLimitOptionValue() as OptionValueInformation,
196+
Validator("config_parse_route_section", "ROUTE_METRIC_INITRWND") to ConfigParseRouteSectionInitRwndOptionValue() as OptionValueInformation,
197+
Validator("config_parse_route_section", "ROUTE_METRIC_QUICKACK") to ConfigParseRouteSectionBooleanOptionValue() as OptionValueInformation,
198+
Validator("config_parse_route_section", "ROUTE_NEXTHOP") to ConfigParseRouteSectionUint32OptionValue() as OptionValueInformation,
199+
Validator("config_parse_route_section", "ROUTE_PREFERENCE") to ConfigParseRouteSectionPreferenceOptionValue() as OptionValueInformation,
200+
Validator("config_parse_route_section", "ROUTE_PRIORITY") to ConfigParseRouteSectionUint32OptionValue() as OptionValueInformation,
201+
Validator("config_parse_route_section", "ROUTE_PROTOCOL") to ConfigParseRouteSectionProtocolOptionValue() as OptionValueInformation,
200202
Validator("config_parse_route_section", "ROUTE_TYPE") to ConfigParseRouteSectionOptionValue() as OptionValueInformation,
201203
Validator("config_parse_router_preference", "0") to ConfigParseRouterPreferenceOptionValue() as OptionValueInformation,
202204
Validator("config_parse_rx_tx_queues", "0") to ConfigParseRxTxQueuesOptionValue() as OptionValueInformation,
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
package net.sjrx.intellij.plugins.systemdunitfiles.semanticdata.optionvalues.ai
2+
3+
import net.sjrx.intellij.plugins.systemdunitfiles.semanticdata.optionvalues.SimpleGrammarOptionValues
4+
import net.sjrx.intellij.plugins.systemdunitfiles.semanticdata.optionvalues.grammar.*
5+
6+
/**
7+
* Boolean route metrics: Route.QuickAck and Route.FastOpenNoCookie
8+
* (config_parse_route_metric_boolean).
9+
*/
10+
class ConfigParseRouteSectionBooleanOptionValue : SimpleGrammarOptionValues(
11+
"config_parse_route_section",
12+
SequenceCombinator(BOOLEAN, EOF())
13+
)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
package net.sjrx.intellij.plugins.systemdunitfiles.semanticdata.optionvalues.ai
2+
3+
import net.sjrx.intellij.plugins.systemdunitfiles.semanticdata.optionvalues.SimpleGrammarOptionValues
4+
import net.sjrx.intellij.plugins.systemdunitfiles.semanticdata.optionvalues.grammar.*
5+
6+
/**
7+
* Validator for [Network] Gateway= (config_parse_route_section, ltype ROUTE_GATEWAY_NETWORK).
8+
*
9+
* systemd.network(5): "The gateway address, which must be in the format described in inet_pton(3).
10+
* This is a short-hand for a [Route] section only containing a Gateway= key."
11+
*
12+
* So it accepts an IPv4 or IPv6 address only — unlike [Route] Gateway=, the special "_dhcp4" /
13+
* "_ipv6ra" tokens are NOT accepted in the [Network] short-hand.
14+
*/
15+
class ConfigParseRouteSectionGatewayNetworkOptionValue : SimpleGrammarOptionValues(
16+
"config_parse_route_section",
17+
SequenceCombinator(
18+
AlternativeCombinator(IPV4_ADDR, IPV6_ADDR),
19+
EOF()
20+
)
21+
)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
package net.sjrx.intellij.plugins.systemdunitfiles.semanticdata.optionvalues.ai
2+
3+
import net.sjrx.intellij.plugins.systemdunitfiles.semanticdata.optionvalues.SimpleGrammarOptionValues
4+
import net.sjrx.intellij.plugins.systemdunitfiles.semanticdata.optionvalues.grammar.*
5+
6+
/**
7+
* Validator for [Route] Gateway= (config_parse_route_section, ltype ROUTE_GATEWAY).
8+
*
9+
* systemd.network(5): "Takes the gateway address or the special values "_dhcp4" and "_ipv6ra". If
10+
* "_dhcp4" or "_ipv6ra" is set, then the gateway address provided by DHCPv4 or IPv6 RA is used."
11+
*/
12+
class ConfigParseRouteSectionGatewayOptionValue : SimpleGrammarOptionValues(
13+
"config_parse_route_section",
14+
SequenceCombinator(
15+
AlternativeCombinator(
16+
IPV4_ADDR,
17+
IPV6_ADDR,
18+
LiteralChoiceTerminal("_dhcp4"),
19+
LiteralChoiceTerminal("_ipv6ra")
20+
),
21+
EOF()
22+
)
23+
)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
package net.sjrx.intellij.plugins.systemdunitfiles.semanticdata.optionvalues.ai
2+
3+
import net.sjrx.intellij.plugins.systemdunitfiles.semanticdata.optionvalues.SimpleGrammarOptionValues
4+
import net.sjrx.intellij.plugins.systemdunitfiles.semanticdata.optionvalues.grammar.*
5+
6+
/**
7+
* Route.HopLimit: an unsigned integer in 1..255 (config_parse_route_metric_hop_limit rejects 0 and
8+
* values above 255).
9+
*/
10+
class ConfigParseRouteSectionHopLimitOptionValue : SimpleGrammarOptionValues(
11+
"config_parse_route_section",
12+
SequenceCombinator(IntegerTerminal(1, 256), EOF())
13+
)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
package net.sjrx.intellij.plugins.systemdunitfiles.semanticdata.optionvalues.ai
2+
3+
import net.sjrx.intellij.plugins.systemdunitfiles.semanticdata.optionvalues.SimpleGrammarOptionValues
4+
import net.sjrx.intellij.plugins.systemdunitfiles.semanticdata.optionvalues.grammar.*
5+
6+
/**
7+
* Route.InitialAdvertisedReceiveWindow: a TCP window in 1..1023 (config_parse_tcp_window rejects 0
8+
* and values of 1024 or more).
9+
*/
10+
class ConfigParseRouteSectionInitRwndOptionValue : SimpleGrammarOptionValues(
11+
"config_parse_route_section",
12+
SequenceCombinator(IntegerTerminal(1, 1024), EOF())
13+
)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
package net.sjrx.intellij.plugins.systemdunitfiles.semanticdata.optionvalues.ai
2+
3+
import net.sjrx.intellij.plugins.systemdunitfiles.semanticdata.optionvalues.SimpleGrammarOptionValues
4+
import net.sjrx.intellij.plugins.systemdunitfiles.semanticdata.optionvalues.grammar.*
5+
6+
/**
7+
* Route.IPv6Preference: one of low, medium, high (config_parse_route_preference).
8+
*/
9+
class ConfigParseRouteSectionPreferenceOptionValue : SimpleGrammarOptionValues(
10+
"config_parse_route_section",
11+
SequenceCombinator(LiteralChoiceTerminal("low", "medium", "high"), EOF())
12+
)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
package net.sjrx.intellij.plugins.systemdunitfiles.semanticdata.optionvalues.ai
2+
3+
import net.sjrx.intellij.plugins.systemdunitfiles.semanticdata.optionvalues.SimpleGrammarOptionValues
4+
import net.sjrx.intellij.plugins.systemdunitfiles.semanticdata.optionvalues.grammar.*
5+
6+
/**
7+
* Route.Protocol: "kernel", "boot", "static", or a number 0-255. systemd uses
8+
* route_protocol_from_string — a small string table with a numeric fallback up to UINT8_MAX.
9+
*/
10+
class ConfigParseRouteSectionProtocolOptionValue : SimpleGrammarOptionValues(
11+
"config_parse_route_section",
12+
SequenceCombinator(
13+
AlternativeCombinator(
14+
LiteralChoiceTerminal("kernel", "boot", "static"),
15+
IntegerTerminal(0, 256)
16+
),
17+
EOF()
18+
)
19+
)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
package net.sjrx.intellij.plugins.systemdunitfiles.semanticdata.optionvalues.ai
2+
3+
import net.sjrx.intellij.plugins.systemdunitfiles.semanticdata.optionvalues.SimpleGrammarOptionValues
4+
import net.sjrx.intellij.plugins.systemdunitfiles.semanticdata.optionvalues.grammar.*
5+
6+
/**
7+
* Route-section options taking an unsigned 32-bit integer: Route.Metric (config_parse_route_priority,
8+
* safe_atou32) and Route.NextHop (config_parse_route_nexthop, a nexthop id).
9+
*/
10+
class ConfigParseRouteSectionUint32OptionValue : SimpleGrammarOptionValues(
11+
"config_parse_route_section",
12+
SequenceCombinator(IntegerTerminal(0, 4_294_967_296), EOF())
13+
)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
package net.sjrx.intellij.plugins.systemdunitfiles.inspections.ai
2+
3+
import net.sjrx.intellij.plugins.systemdunitfiles.AbstractUnitFileTest
4+
import net.sjrx.intellij.plugins.systemdunitfiles.inspections.InvalidValueInspection
5+
import org.junit.Test
6+
7+
/**
8+
* Gateway= coverage for systemd .network files (config_parse_route_section, ltypes ROUTE_GATEWAY
9+
* and ROUTE_GATEWAY_NETWORK). Previously unregistered, so Gateway values were not validated at all.
10+
*
11+
* [Network] Gateway= is an IPv4/IPv6 address only; [Route] Gateway= also accepts "_dhcp4"/"_ipv6ra".
12+
*/
13+
class ConfigParseRouteSectionGatewayOptionValueTest : AbstractUnitFileTest() {
14+
15+
@Test
16+
fun testValidGateways() {
17+
// language="unit file (systemd)"
18+
val file = """
19+
[Network]
20+
Gateway=192.168.1.1
21+
Gateway=2001:db8::1
22+
[Route]
23+
Gateway=10.0.0.1
24+
Gateway=fe80::1
25+
Gateway=_dhcp4
26+
Gateway=_ipv6ra
27+
""".trimIndent()
28+
29+
setupFileInEditor("file.network", file)
30+
enableInspection(InvalidValueInspection::class.java)
31+
32+
assertSize(0, myFixture.doHighlighting())
33+
}
34+
35+
@Test
36+
fun testInvalidGateways() {
37+
// [Network] does not accept the special tokens; bad addresses are rejected in both sections;
38+
// [Route] only accepts _dhcp4 / _ipv6ra (not _dhcp6). One highlight per line.
39+
// language="unit file (systemd)"
40+
val file = """
41+
[Network]
42+
Gateway=_dhcp4
43+
Gateway=notanip
44+
[Route]
45+
Gateway=_dhcp6
46+
Gateway=300.1.2.3
47+
""".trimIndent()
48+
49+
setupFileInEditor("file.network", file)
50+
enableInspection(InvalidValueInspection::class.java)
51+
52+
assertSize(4, myFixture.doHighlighting())
53+
}
54+
}

0 commit comments

Comments
 (0)