Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Enable networking with vnet #35

Merged
merged 6 commits into from
Dec 4, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .cirrus.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,9 @@ task:
- pkg install -y git-lite go golangci-lint
- go env -w GOMODCACHE=$(pwd)/.gomodcache
- go mod download
- sudo touch /etc/pf.conf
- echo 'pf_enable="YES"' | sudo tee -a /etc/rc.conf
- sudo service pf start
build_script:
- make
test_script:
Expand Down
12 changes: 9 additions & 3 deletions cmd/runj/create.go
Original file line number Diff line number Diff line change
Expand Up @@ -166,9 +166,15 @@ written`)
Root: rootPath,
Hostname: ociConfig.Hostname,
}
if ociConfig.FreeBSD != nil && ociConfig.FreeBSD.Network != nil && ociConfig.FreeBSD.Network.IPv4 != nil {
jailcfg.IP4 = string(ociConfig.FreeBSD.Network.IPv4.Mode)
jailcfg.IP4Addr = ociConfig.FreeBSD.Network.IPv4.Addr
if ociConfig.FreeBSD != nil && ociConfig.FreeBSD.Network != nil {
if ociConfig.FreeBSD.Network.IPv4 != nil {
jailcfg.IP4 = string(ociConfig.FreeBSD.Network.IPv4.Mode)
jailcfg.IP4Addr = ociConfig.FreeBSD.Network.IPv4.Addr
}
if ociConfig.FreeBSD.Network.VNet != nil {
jailcfg.VNet = string(ociConfig.FreeBSD.Network.VNet.Mode)
jailcfg.VNetInterface = ociConfig.FreeBSD.Network.VNet.Interfaces
}
}

var confPath string
Expand Down
1 change: 0 additions & 1 deletion cmd/runj/demo.go
Original file line number Diff line number Diff line change
Expand Up @@ -122,7 +122,6 @@ func downloadImage(arch, version string, f *os.File) error {
_, err = io.Copy(f, barReader)
bar.Finish()
return err

}

func specCommand() *cobra.Command {
Expand Down
49 changes: 25 additions & 24 deletions cmd/runj/state.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,33 +22,34 @@ import (
//
// The state of a container includes the following properties:
//
// * ociVersion (string, REQUIRED) is version of the Open Container Initiative
// Runtime Specification with which the state complies.
// * id (string, REQUIRED) is the container's ID. This MUST be unique across all
// containers on this host. There is no requirement that it be unique across
// hosts.
// * status (string, REQUIRED) is the runtime state of the container. The value
// MAY be one of:
// * creating: the container is being created (step 2 in the lifecycle)
// * created: the runtime has finished the create operation (after step 2 in
// - ociVersion (string, REQUIRED) is version of the Open Container Initiative
// Runtime Specification with which the state complies.
// - id (string, REQUIRED) is the container's ID. This MUST be unique across all
// containers on this host. There is no requirement that it be unique across
// hosts.
// - status (string, REQUIRED) is the runtime state of the container. The value
// MAY be one of:
// - creating: the container is being created (step 2 in the lifecycle)
// - created: the runtime has finished the create operation (after step 2 in
// the lifecycle), and the container process has neither exited nor executed
// the user-specified program
// * running: the container process has executed the user-specified program
// - running: the container process has executed the user-specified program
// but has not exited (after step 5 in the lifecycle)
// * stopped: the container process has exited (step 7 in the lifecycle)
// Additional values MAY be defined by the runtime, however, they MUST be used
// to represent new runtime states not defined above.
// * pid (int, REQUIRED when status is created or running on Linux, OPTIONAL on
// other platforms) is the ID of the container process. For hooks executed in
// the runtime namespace, it is the pid as seen by the runtime. For hooks
// executed in the container namespace, it is the pid as seen by the
// container.
// * bundle (string, REQUIRED) is the absolute path to the container's bundle
// directory. This is provided so that consumers can find the container's
// configuration and root filesystem on the host.
// * annotations (map, OPTIONAL) contains the list of annotations associated
// with the container. If no annotations were provided then this property MAY
// either be absent or an empty map.
// - stopped: the container process has exited (step 7 in the lifecycle)
// Additional values MAY be defined by the runtime, however, they MUST be used
// to represent new runtime states not defined above.
// - pid (int, REQUIRED when status is created or running on Linux, OPTIONAL on
// other platforms) is the ID of the container process. For hooks executed in
// the runtime namespace, it is the pid as seen by the runtime. For hooks
// executed in the container namespace, it is the pid as seen by the
// container.
// - bundle (string, REQUIRED) is the absolute path to the container's bundle
// directory. This is provided so that consumers can find the container's
// configuration and root filesystem on the host.
// - annotations (map, OPTIONAL) contains the list of annotations associated
// with the container. If no annotations were provided then this property MAY
// either be absent or an empty map.
//
// The state MAY include additional properties.
func stateCommand() *cobra.Command {
return &cobra.Command{
Expand Down
15 changes: 15 additions & 0 deletions docs/oci.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ Fields inside the `freebsd` struct:

Fields inside the `network` struct:
* `ipv4` (struct)
* `vnet` (struct)

Fields inside the `ipv4` struct:
* `mode` (string) - valid options are `new`, `inherit`, and `disable`. This
Expand All @@ -21,6 +22,13 @@ Fields inside the `ipv4` struct:
is the equivalent of the `ip4.addr` field described in the `jail(8)` manual
page.

Fields inside the `vnet` struct:
* `mode` (string) - valid options are `new` and `inherit`. This field is the
equivalent of the `vnet` field described in the `jail(8)` manual page.
* `interfaces` ([]string) - list of network interfaces assigned to the jail.
This field is the equivalent of the `vnet.interface` field described in the
`jail(8)` manual page.

If embedded in the normal `config.json`, an example would look as follows:

```json
Expand All @@ -34,6 +42,10 @@ If embedded in the normal `config.json`, an example would look as follows:
"ipv4": {
"mode": "new",
"addr": ["127.0.0.2"]
},
"vnet": {
"mode": "new",
"interfaces": ["epair0b"]
}
}
}
Expand All @@ -47,6 +59,9 @@ If included in a separate `runj.ext.json`, an example would look as follows:
"network": {
"ipv4": {
"mode": "inherit"
},
"vnet": {
"mode": "inherit"
}
}
}
Expand Down
18 changes: 13 additions & 5 deletions jail/conf.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,12 @@ const (
{{- end }}
{{- if gt (len .IP4Addr) 0 }}
ip4.addr = {{ join .IP4Addr ", " }};
{{- end }}
{{- if ne .VNet "" }}
vnet = "{{.VNet}}";
{{- end }}
{{- if gt (len .VNetInterface) 0 }}
vnet.interface = "{{ join .VNetInterface ", " }}";
{{- end }}
persist;
}
Expand All @@ -31,11 +37,13 @@ const (

// Config is a limited subset of the parameters available in jail.conf(5) for use with jail(8).
type Config struct {
Name string
Root string
Hostname string
IP4 string
IP4Addr []string
Name string
Root string
Hostname string
IP4 string
IP4Addr []string
VNet string
VNetInterface []string
}

// CreateConfig creates a config file for the jail(8) command
Expand Down
10 changes: 9 additions & 1 deletion jail/conf_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,13 +28,21 @@ func TestRenderConfigGolden(t *testing.T) {
Hostname: "test.hostname.example.com",
},
}, {
"network",
"ipv4-network",
Config{
Name: "network",
Root: "/tmp/test/network/root",
IP4: "new",
IP4Addr: []string{"one", "two", "three"},
},
}, {
"vnet",
Config{
Name: "vnet",
Root: "/tmp/test/vnet/root",
VNet: "new",
VNetInterface: []string{"epair0b", "epair1b"},
},
}}
for _, tc := range tests {
t.Run(tc.name, func(t *testing.T) {
Expand Down
File renamed without changes.
6 changes: 6 additions & 0 deletions jail/testdata/vnet.conf
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
vnet {
path = "/tmp/test/vnet/root";
vnet = "new";
vnet.interface = "epair0b, epair1b";
persist;
}
11 changes: 11 additions & 0 deletions oci/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -95,5 +95,16 @@ func merge(spec *runtimespec.Spec, freebsd *runtimespec.FreeBSD) {
spec.FreeBSD.Network.IPv4.Addr = append(spec.FreeBSD.Network.IPv4.Addr, freebsd.Network.IPv4.Addr...)
}
}
if freebsd.Network.VNet != nil {
if spec.FreeBSD.Network.VNet == nil {
spec.FreeBSD.Network.VNet = &runtimespec.FreeBSDVNet{}
}
if freebsd.Network.VNet.Mode != "" {
spec.FreeBSD.Network.VNet.Mode = freebsd.Network.VNet.Mode
}
if len(freebsd.Network.VNet.Interfaces) > 0 {
spec.FreeBSD.Network.VNet.Interfaces = append(spec.FreeBSD.Network.VNet.Interfaces, freebsd.Network.VNet.Interfaces...)
}
}
}
}
21 changes: 20 additions & 1 deletion runtimespec/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -154,6 +154,7 @@ type FreeBSD struct {
// kernel
type FreeBSDNetwork struct {
IPv4 *FreeBSDIPv4 `json:"ipv4,omitempty"`
VNet *FreeBSDVNet `json:"vnet,omitempty"`
}

// FreeBSDIPv4 encapsulates IPv4-specific jail options
Expand All @@ -162,7 +163,7 @@ type FreeBSDIPv4 struct {
// "inherit", and "disable". Setting the Addr parameter implies a value of
// "new".
Mode FreeBSDIPv4Mode `json:"mode,omitempty"`
// Addr is a list of IPv4 addresses assigned ot the jail. If this is set,
// Addr is a list of IPv4 addresses assigned to the jail. If this is set,
// the jail is restricted to using only these addresses.
Addr []string `json:"addr,omitempty"`
}
Expand All @@ -178,6 +179,24 @@ const (
FreeBSDIPv4ModeDisable = "disable"
)

// FreeBSDVNet encapsulates vnet-specific jail options
type FreeBSDVNet struct {
// Mode specifies the vnet mode of the jail. Possible values are "new" and
// "inherit". Setting the Interfaces parameter implies a value of "new".
Mode FreeBSDVNetMode `json:"mode,omitempty"`
// Interfaces is a list of interfaces assigned to the jail. If this is set,
// the interfaces are moved into the jail and are inaccessible from the
// host.
Interfaces []string `json:"interfaces,omitempty"`
}

const (
FreeBSDVNetModeNew FreeBSDVNetMode = "new"
FreeBSDVNetModeInherit = "inherit"
)

type FreeBSDVNetMode string

// End of modification

// Modification by Samuel Karp
Expand Down
22 changes: 22 additions & 0 deletions test/integration/inside_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import (
"io/ioutil"
"net/http"
"os"
"os/exec"
"testing"

"github.com/stretchr/testify/assert"
Expand Down Expand Up @@ -53,3 +54,24 @@ func TestLocalhostHTTPHello(t *testing.T) {
assert.NoError(t, err, "failed to read body")
fmt.Println(string(body))
}

func TestVnetConfigAndPing(t *testing.T) {
var (
iface = os.Getenv("TEST_INTERFACE")
ip = os.Getenv("TEST_IP")
mask = os.Getenv("TEST_MASK")
gateway = os.Getenv("TEST_GATEWAY")
pingIP = os.Getenv("TEST_PING_IP")
)
out, err := exec.Command("/sbin/ifconfig", iface, "inet", ip+"/"+mask).CombinedOutput()
t.Logf("ifconfig %s inet %s/%s: %s", iface, ip, mask, string(out))
assert.NoError(t, err)

out, err = exec.Command("/sbin/route", "-4", "add", "default", gateway).CombinedOutput()
t.Logf("route -4 add default %s: %s", ip, string(out))
assert.NoError(t, err)

out, err = exec.Command("/sbin/ping", "-c2", pingIP).CombinedOutput()
t.Logf("ping -c2 %s: %s", pingIP, string(out))
assert.NoError(t, err)
}
Loading