Skip to content

Commit 06a3136

Browse files
authored
Merge pull request #1615 from ibot3/routed-nic-vrf
Add `vrf` parameter for routed-nic devices
2 parents b1d4d6a + adede11 commit 06a3136

File tree

11 files changed

+118
-8
lines changed

11 files changed

+118
-8
lines changed

.github/workflows/tests.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -267,6 +267,7 @@ jobs:
267267
libsqlite3-dev \
268268
libtool \
269269
libudev-dev \
270+
linux-modules-extra-$(uname -r) \
270271
make \
271272
pkg-config\
272273
acl \

doc/.wordlist.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -326,6 +326,7 @@ VMs
326326
VPD
327327
VPN
328328
VPS
329+
VRF
329330
vSwitch
330331
VXLAN
331332
WebSocket

doc/api-extensions.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2699,3 +2699,6 @@ This API extension provides the ability to configure storage volumes in preseed
26992699

27002700
## `init_preseed_profile_project`
27012701
This API extension provides the ability to specify the project as part of profile definitions in preseed init.
2702+
2703+
## `instance_nic_routed_host_address`
2704+
Adds support for specifying the VRF to add the routes to.

doc/reference/devices_nic.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -450,6 +450,7 @@ Key | Type | Default | Description
450450
`parent` | string | - | The name of the host device to join the instance to
451451
`queue.tx.length` | integer | - | The transmit queue length for the NIC
452452
`vlan` | integer | - | The VLAN ID to attach to
453+
`vrf` | string | - | The VRF on the host in which the host-side interface and routes are created
453454
454455
## `bridged`, `macvlan` or `ipvlan` for connection to physical network
455456

internal/server/device/device_utils_network.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -222,6 +222,7 @@ func networkCreateVethPair(hostName string, m deviceConfig.Device) (string, uint
222222
Peer: ip.Link{
223223
Name: network.RandomDevName("veth"),
224224
},
225+
Master: m["vrf"],
225226
}
226227

227228
// Set the MTU on both ends.
@@ -308,6 +309,7 @@ func networkCreateTap(hostName string, m deviceConfig.Device) (uint32, error) {
308309
Name: hostName,
309310
Mode: "tap",
310311
MultiQueue: true,
312+
Master: m["vrf"],
311313
}
312314

313315
err := tuntap.Add()

internal/server/device/nic_routed.go

Lines changed: 20 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,7 @@ func (d *nicRouted) validateConfig(instConf instance.ConfigReader) error {
8080
"ipv4.host_table",
8181
"ipv6.host_table",
8282
"gvrp",
83+
"vrf",
8384
}
8485

8586
rules := nicValidationRules(requiredFields, optionalFields, instConf)
@@ -88,6 +89,7 @@ func (d *nicRouted) validateConfig(instConf instance.ConfigReader) error {
8889
rules["gvrp"] = validate.Optional(validate.IsBool)
8990
rules["ipv4.neighbor_probe"] = validate.Optional(validate.IsBool)
9091
rules["ipv6.neighbor_probe"] = validate.Optional(validate.IsBool)
92+
rules["vrf"] = validate.Optional(validate.IsAny)
9193

9294
err = d.config.Validate(rules)
9395
if err != nil {
@@ -216,6 +218,13 @@ func (d *nicRouted) validateEnvironment() error {
216218
}
217219
}
218220

221+
if d.config["vrf"] != "" {
222+
// Check if the vrf interface exists.
223+
if !network.InterfaceExists(d.config["vrf"]) {
224+
return fmt.Errorf("VRF %q doesn't exist", d.config["vrf"])
225+
}
226+
}
227+
219228
return nil
220229
}
221230

@@ -405,14 +414,20 @@ func (d *nicRouted) Start() (*deviceConfig.RunConfig, error) {
405414
}
406415
}
407416

417+
table := "main"
418+
if d.config["vrf"] != "" {
419+
table = ""
420+
}
421+
408422
// Perform per-address host-side configuration (static routes and neighbour proxy entries).
409423
for _, addrStr := range addresses {
410-
// Apply host-side static routes to main routing table.
424+
// Apply host-side static routes to main routing table or VRF.
411425
r := ip.Route{
412426
DevName: saveData["host_name"],
413427
Route: fmt.Sprintf("%s/%d", addrStr, subnetSize),
414-
Table: "main",
428+
Table: table,
415429
Family: ipFamilyArg,
430+
VRF: d.config["vrf"],
416431
}
417432

418433
err = r.Add()
@@ -462,13 +477,14 @@ func (d *nicRouted) Start() (*deviceConfig.RunConfig, error) {
462477
}
463478
// Add routes
464479
for _, routeStr := range routes {
465-
// Apply host-side static routes to main routing table.
480+
// Apply host-side static routes to main routing table or VRF.
466481
r := ip.Route{
467482
DevName: saveData["host_name"],
468483
Route: routeStr,
469-
Table: "main",
484+
Table: table,
470485
Family: ipFamilyArg,
471486
Via: addresses[0],
487+
VRF: d.config["vrf"],
472488
}
473489

474490
err = r.Add()

internal/server/ip/link_veth.go

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,30 @@
11
package ip
22

3+
import (
4+
"github.com/lxc/incus/v6/shared/subprocess"
5+
)
6+
37
// Veth represents arguments for link of type veth.
48
type Veth struct {
59
Link
6-
Peer Link
10+
Peer Link
11+
Master string
712
}
813

914
// Add adds new virtual link.
1015
func (veth *Veth) Add() error {
11-
return veth.Link.add("veth", append([]string{"peer"}, veth.Peer.args()...))
16+
err := veth.Link.add("veth", append([]string{"peer"}, veth.Peer.args()...))
17+
18+
if err != nil {
19+
return err
20+
}
21+
22+
if veth.Master != "" {
23+
_, err := subprocess.RunCommand("ip", "link", "set", veth.Name, "master", veth.Master)
24+
if err != nil {
25+
return err
26+
}
27+
}
28+
29+
return nil
1230
}

internal/server/ip/route.go

Lines changed: 31 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ type Route struct {
1515
Proto string
1616
Family string
1717
Via string
18+
VRF string
1819
}
1920

2021
// Add adds new route.
@@ -37,6 +38,10 @@ func (r *Route) Add() error {
3738
cmd = append(cmd, "proto", r.Proto)
3839
}
3940

41+
if r.VRF != "" {
42+
cmd = append(cmd, "vrf", r.VRF)
43+
}
44+
4045
_, err := subprocess.RunCommand("ip", cmd...)
4146
if err != nil {
4247
return err
@@ -47,7 +52,15 @@ func (r *Route) Add() error {
4752

4853
// Delete deletes routing table.
4954
func (r *Route) Delete() error {
50-
_, err := subprocess.RunCommand("ip", r.Family, "route", "delete", "table", r.Table, r.Route, "dev", r.DevName)
55+
cmd := []string{r.Family, "route", "delete", r.Route, "dev", r.DevName}
56+
57+
if r.VRF != "" {
58+
cmd = append(cmd, "vrf", r.VRF)
59+
} else if r.Table != "" {
60+
cmd = append(cmd, "table", r.Table)
61+
}
62+
63+
_, err := subprocess.RunCommand("ip", cmd...)
5164
if err != nil {
5265
return err
5366
}
@@ -76,6 +89,10 @@ func (r *Route) Flush() error {
7689
cmd = append(cmd, "proto", r.Proto)
7790
}
7891

92+
if r.VRF != "" {
93+
cmd = append(cmd, "vrf", r.VRF)
94+
}
95+
7996
_, err := subprocess.RunCommand("ip", cmd...)
8097
if err != nil {
8198
return err
@@ -87,6 +104,11 @@ func (r *Route) Flush() error {
87104
// Replace changes or adds new route.
88105
func (r *Route) Replace(routes []string) error {
89106
cmd := []string{r.Family, "route", "replace", "dev", r.DevName, "proto", r.Proto}
107+
108+
if r.VRF != "" {
109+
cmd = append(cmd, "vrf", r.VRF)
110+
}
111+
90112
cmd = append(cmd, routes...)
91113
_, err := subprocess.RunCommand("ip", cmd...)
92114
if err != nil {
@@ -99,7 +121,14 @@ func (r *Route) Replace(routes []string) error {
99121
// Show lists routes.
100122
func (r *Route) Show() ([]string, error) {
101123
routes := []string{}
102-
out, err := subprocess.RunCommand("ip", r.Family, "route", "show", "dev", r.DevName, "proto", r.Proto)
124+
125+
cmd := []string{r.Family, "route", "show", "dev", r.DevName, "proto", r.Proto}
126+
127+
if r.VRF != "" {
128+
cmd = append(cmd, "vrf", r.VRF)
129+
}
130+
131+
out, err := subprocess.RunCommand("ip", cmd...)
103132
if err != nil {
104133
return routes, err
105134
}

internal/server/ip/tuntap.go

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ type Tuntap struct {
99
Name string
1010
Mode string
1111
MultiQueue bool
12+
Master string
1213
}
1314

1415
// Add adds new tuntap interface.
@@ -23,5 +24,12 @@ func (t *Tuntap) Add() error {
2324
return err
2425
}
2526

27+
if t.Master != "" {
28+
_, err := subprocess.RunCommand("ip", "link", "set", t.Name, "master", t.Master)
29+
if err != nil {
30+
return err
31+
}
32+
}
33+
2634
return nil
2735
}

internal/version/api.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -461,6 +461,7 @@ var APIExtensions = []string{
461461
"instance_debug_memory",
462462
"init_preseed_storage_volumes",
463463
"init_preseed_profile_project",
464+
`instance_nic_routed_host_address`,
464465
}
465466

466467
// APIExtensionsCount returns the number of available API extensions.

0 commit comments

Comments
 (0)