Skip to content
Open
Show file tree
Hide file tree
Changes from 2 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
15 changes: 15 additions & 0 deletions pkg/unikontainers/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ const (
annotBlock = "com.urunc.unikernel.block"
annotBlockMntPoint = "com.urunc.unikernel.blkMntPoint"
annotMountRootfs = "com.urunc.unikernel.mountRootfs"
annotNetDev = "com.urunc.unikernel.netDev"

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since this is Solo5 specific, I would suggest to add a Solo5 prefix (e.g. Solo5NetDevName).

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Prefixed the Go identifiers as suggested. I'm assuming you want the annotation key to stay as com.urunc.unikernel.netDev?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actually, I meant the annotation key to have a prefix

)

// A UnikernelConfig struct holds the info provided by bima image on how to execute our unikernel
Expand All @@ -58,6 +59,7 @@ type UnikernelConfig struct {
Block string `json:"com.urunc.unikernel.block,omitempty"`
BlkMntPoint string `json:"com.urunc.unikernel.blkMntPoint,omitempty"`
MountRootfs string `json:"com.urunc.unikernel.mountRootfs"`
NetDev string `json:"com.urunc.unikernel.netDev,omitempty"`

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

}

// validate checks if the mandatory configuration fields are present.
Expand Down Expand Up @@ -127,6 +129,7 @@ func getConfigFromSpec(spec *specs.Spec) *UnikernelConfig {
block := spec.Annotations[annotBlock]
blkMntPoint := spec.Annotations[annotBlockMntPoint]
MountRootfs := spec.Annotations[annotMountRootfs]
netDev := spec.Annotations[annotNetDev]
uniklog.WithFields(logrus.Fields{
"unikernelType": tryDecode(unikernelType),
"unikernelVersion": tryDecode(unikernelVersion),
Expand All @@ -137,6 +140,7 @@ func getConfigFromSpec(spec *specs.Spec) *UnikernelConfig {
"block": tryDecode(block),
"blkMntPoint": tryDecode(blkMntPoint),
"mountRootfs": tryDecode(MountRootfs),
"netDev": tryDecode(netDev),
}).WithField("source", "spec").Debug("urunc annotations")

return &UnikernelConfig{
Expand All @@ -149,6 +153,7 @@ func getConfigFromSpec(spec *specs.Spec) *UnikernelConfig {
Block: block,
BlkMntPoint: blkMntPoint,
MountRootfs: MountRootfs,
NetDev: netDev,
}
}

Expand Down Expand Up @@ -188,6 +193,7 @@ func getConfigFromJSON(jsonFilePath string) (*UnikernelConfig, error) {
"block": tryDecode(conf.Block),
"blkMntPoint": tryDecode(conf.BlkMntPoint),
"mountRootfs": tryDecode(conf.MountRootfs),
"netDev": tryDecode(conf.NetDev),
}).WithField("source", uruncJSONFilename).Debug("urunc annotations")

return &conf, nil
Expand Down Expand Up @@ -258,6 +264,12 @@ func (c *UnikernelConfig) decode() error {
}
c.MountRootfs = string(decoded)

decoded, err = base64.StdEncoding.DecodeString(c.NetDev)
if err != nil {
return fmt.Errorf("failed to decode netDev: %v", err)
}
c.NetDev = string(decoded)

return nil
}

Expand Down Expand Up @@ -291,6 +303,9 @@ func (c *UnikernelConfig) Map() map[string]string {
if c.MountRootfs != "" {
myMap[annotMountRootfs] = c.MountRootfs
}
if c.NetDev != "" {
myMap[annotNetDev] = c.NetDev
}

return myMap
}
4 changes: 4 additions & 0 deletions pkg/unikontainers/config_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ func TestGetConfigFromSpec(t *testing.T) {
annotBlock: "block1",
annotBlockMntPoint: "point1",
annotMountRootfs: "true",
annotNetDev: "mynetdev",
},
}

Expand All @@ -50,6 +51,7 @@ func TestGetConfigFromSpec(t *testing.T) {
Block: "block1",
BlkMntPoint: "point1",
MountRootfs: "true",
NetDev: "mynetdev",
}

config := getConfigFromSpec(spec)
Expand Down Expand Up @@ -239,6 +241,7 @@ func TestMap(t *testing.T) {
Block: "block_value",
BlkMntPoint: "point_value",
MountRootfs: "false",
NetDev: "netdev_value",
}
expectedMap := map[string]string{
annotCmdLine: "cmd_value",
Expand All @@ -249,6 +252,7 @@ func TestMap(t *testing.T) {
annotBlock: "block_value",
annotBlockMntPoint: "point_value",
annotMountRootfs: "false",
annotNetDev: "netdev_value",
}
resultMap := config.Map()
assert.Equal(t, expectedMap, resultMap)
Expand Down
1 change: 1 addition & 0 deletions pkg/unikontainers/types/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,7 @@ type UnikernelParams struct {
Monitor string // The monitor where guest will execute
Version string // The version of the unikernel
InitrdPath string // The path to the initrd of the unikernel
NetDevName string // The name of the guest network device declared at build time
Net NetDevParams
Block []BlockDevParams
Rootfs RootfsParams // Information about rootfs
Expand Down
29 changes: 21 additions & 8 deletions pkg/unikontainers/unikernels/mirage.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,10 +24,11 @@ import (
const MirageUnikernel string = "mirage"

type Mirage struct {
Command string
Monitor string
Net MirageNet
Block []MirageBlock
Command string
Monitor string
Net MirageNet
Block []MirageBlock
netDevName string
}

type MirageNet struct {
Expand Down Expand Up @@ -57,8 +58,9 @@ func (m *Mirage) SupportsFS(_ string) bool {
func (m *Mirage) MonitorNetCli(ifName string, mac string) string {
switch m.Monitor {
case "hvt", "spt":
netOption := "--net:service=" + ifName
netOption += " --net-mac:service=" + mac
name := m.netDevName

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No reason for this assignment.

netOption := "--net:" + name + "=" + ifName
netOption += " --net-mac:" + name + "=" + mac
return netOption
default:
return ""
Expand Down Expand Up @@ -99,8 +101,13 @@ func (m *Mirage) MonitorCli() types.MonitorCliArgs {
func (m *Mirage) Init(data types.UnikernelParams) error {
// if Mask is empty, there is no network support
if data.Net.Mask != "" {
m.Net.Address = "--ipv4=" + data.Net.IP + "/24"
m.Net.Gateway = "--ipv4-gateway=" + data.Net.Gateway
if data.NetDevName != "" && data.NetDevName != "service" {
m.Net.Address = "--" + data.NetDevName + "-ipv4=" + data.Net.IP + "/24"
m.Net.Gateway = "--" + data.NetDevName + "-ipv4-gateway=" + data.Net.Gateway
} else {
m.Net.Address = "--ipv4=" + data.Net.IP + "/24"
m.Net.Gateway = "--ipv4-gateway=" + data.Net.Gateway
}
}
Comment on lines 102 to 115

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In Mirage you can "group" parameters to network devices. What this effectively means is that you can add a prefix to the command line options (often the interface name). An example is for an interface management you'd often add a group management and this would produce command line options --management-ipv4, --management-ipv4-gateway etc. Now, since a recent release of Mirage interfaces will by default use DHCP to acquire this information if it was not presented at boot time (or statically configured) instead of using a silly default of 10.0.0.2/24 and 10.0.0.1 as ipv4 and ipv4-gateway respectively.

So to configure extra interfaces there's no good way to do it, but I think a decent heuristic is for each interface that is not called "service" to use data.NetDevName as the group.

Finally, you can construct unikernels in whatever way you want so you are never guaranteed that the unikernel accepts these options.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yeah makes sense, pushed it as a new commit

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we add this as a comment to explain the cli argument construction? It is useful information.

m.Block = make([]MirageBlock, 0, len(data.Block))
for _, blk := range data.Block {
Expand All @@ -114,6 +121,12 @@ func (m *Mirage) Init(data types.UnikernelParams) error {
m.Command = strings.Join(data.CmdLine, " ")
m.Monitor = data.Monitor

if data.NetDevName != "" {
m.netDevName = data.NetDevName
} else {
m.netDevName = "service"
}

return nil
}

Expand Down
44 changes: 44 additions & 0 deletions pkg/unikontainers/unikernels/mirage_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
// Copyright (c) 2023-2026, Nubificus LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package unikernels

import (
"testing"

"github.com/stretchr/testify/assert"
"github.com/urunc-dev/urunc/pkg/unikontainers/types"
)

func TestMirageNetDevName(t *testing.T) {
t.Run("uses net device name from annotation", func(t *testing.T) {
t.Parallel()
m := &Mirage{}
err := m.Init(types.UnikernelParams{Monitor: "hvt", NetDevName: "mynetdev"})
assert.NoError(t, err)
cli := m.MonitorNetCli("tap0", "aa:bb:cc:dd:ee:ff")
assert.Contains(t, cli, "--net:mynetdev=tap0")
assert.Contains(t, cli, "--net-mac:mynetdev=aa:bb:cc:dd:ee:ff")
})

t.Run("falls back to service when annotation is absent", func(t *testing.T) {
t.Parallel()
m := &Mirage{}
err := m.Init(types.UnikernelParams{Monitor: "hvt"})
assert.NoError(t, err)
cli := m.MonitorNetCli("tap0", "aa:bb:cc:dd:ee:ff")
assert.Contains(t, cli, "--net:service=tap0")
assert.Contains(t, cli, "--net-mac:service=aa:bb:cc:dd:ee:ff")
})
}
11 changes: 6 additions & 5 deletions pkg/unikontainers/unikontainers.go
Original file line number Diff line number Diff line change
Expand Up @@ -380,11 +380,12 @@ func (u *Unikontainer) Exec(metrics m.Writer) error {
// UnikernelParams
// populate unikernel params
unikernelParams := types.UnikernelParams{
CmdLine: u.Spec.Process.Args,
EnvVars: u.Spec.Process.Env,
Monitor: vmmType,
Version: unikernelVersion,
ProcConf: procAttrs,
CmdLine: u.Spec.Process.Args,
EnvVars: u.Spec.Process.Env,
Monitor: vmmType,
Version: unikernelVersion,
ProcConf: procAttrs,
NetDevName: u.State.Annotations[annotNetDev],
}
if len(unikernelParams.CmdLine) == 0 {
unikernelParams.CmdLine = strings.Fields(u.State.Annotations[annotCmdLine])
Expand Down