Skip to content

Commit d9de97c

Browse files
sidneychangurunc-bot[bot]
authored andcommitted
fix: add container veth discovery to replace hardcoded eth0
- Add `discoverContainerIface` in `pkg/network/network.go` to discover the container-side veth endpoint by scanning links in the current netns. - Replace places that relied on the hardcoded `DefaultInterface` with the discovered link. This implements interface discovery instead of assuming `eth0`, improving compatibility across different runtimes/CNIs. Fixes #14 PR: #392 Signed-off-by: sidneychang <2190206983@qq.com> Reviewed-by: Charalampos Mainas <cmainas@nubificus.co.uk> Approved-by: Charalampos Mainas <cmainas@nubificus.co.uk>
1 parent 956f1c2 commit d9de97c

4 files changed

Lines changed: 75 additions & 44 deletions

File tree

‎.github/contributors.yaml‎

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,3 +44,6 @@ users:
4444
IrvingMg:
4545
name: Irving Mondragón
4646
email: mirvingr@gmail.com
47+
sidneychang:
48+
name: Xuedong Zhang
49+
email: 2190206983@qq.com

‎pkg/network/network.go‎

Lines changed: 63 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -27,8 +27,7 @@ import (
2727
)
2828

2929
const (
30-
DefaultInterface = "eth0" // FIXME: Discover the veth endpoint name instead of using default "eth0". See: https://github.com/urunc-dev/urunc/issues/14
31-
DefaultTap = "tapX_urunc"
30+
DefaultTap = "tapX_urunc"
3231
)
3332

3433
var netlog = logrus.WithField("subsystem", "network")
@@ -120,21 +119,6 @@ func createTapDevice(name string, mtu int, ownerUID, ownerGID uint32) (netlink.L
120119
return tapLink, nil
121120
}
122121

123-
// ensureEth0Exists checks all network interfaces in current netns and returns
124-
// nil if eth0 is present or ErrEth0NotFound if not
125-
func ensureEth0Exists() error {
126-
ifaces, err := net.Interfaces()
127-
if err != nil {
128-
return err
129-
}
130-
for _, iface := range ifaces {
131-
if iface.Name == DefaultInterface {
132-
return nil
133-
}
134-
}
135-
return errors.New("eth0 device not found")
136-
}
137-
138122
func getInterfaceInfo(iface string) (Interface, error) {
139123
ief, err := net.InterfaceByName(iface)
140124
if err != nil {
@@ -163,7 +147,7 @@ func getInterfaceInfo(iface string) (Interface, error) {
163147
}
164148
}
165149
if mask == "" {
166-
return Interface{}, fmt.Errorf("failed to find mask for %q", DefaultInterface)
150+
return Interface{}, fmt.Errorf("failed to find mask for %q", iface)
167151
}
168152
// convert to decimal notation
169153
decimalParts := make([]string, len(netMask))
@@ -172,7 +156,7 @@ func getInterfaceInfo(iface string) (Interface, error) {
172156
}
173157
mask = strings.Join(decimalParts, ".")
174158
if ipAddress == "" {
175-
return Interface{}, fmt.Errorf("failed to find IPv4 address for %q", DefaultInterface)
159+
return Interface{}, fmt.Errorf("failed to find IPv4 address for %q", iface)
176160
}
177161
gateway, err := gateway.DiscoverGateway()
178162
if err != nil {
@@ -182,7 +166,7 @@ func getInterfaceInfo(iface string) (Interface, error) {
182166
IP: ipAddress,
183167
DefaultGateway: gateway.String(),
184168
Mask: mask,
185-
Interface: DefaultInterface,
169+
Interface: iface,
186170
MAC: IfMAC,
187171
}, nil
188172
}
@@ -219,14 +203,6 @@ func addRedirectFilter(source netlink.Link, target netlink.Link) error {
219203
func networkSetup(tapName string, ipAddress string, redirectLink netlink.Link, addTCRules bool, uid uint32, gid uint32) (netlink.Link, error) {
220204
netlog.Debugf("starting for tapName=%s ipAddress=%s redirectLink=%s addTCRules=%v",
221205
tapName, ipAddress, redirectLink.Attrs().Name, addTCRules)
222-
223-
// Sanity check: ensure eth0 exists in this namespace
224-
err := ensureEth0Exists()
225-
if err != nil {
226-
netlog.Warnf("eth0 interface not found in namespace (unikernel may have been spawned using ctr): %v", err)
227-
return nil, nil
228-
}
229-
230206
// Create TAP
231207
netlog.Debugf("creating tap device %s (mtu=%d)", tapName, redirectLink.Attrs().MTU)
232208
newTapDevice, err := createTapDevice(tapName, redirectLink.Attrs().MTU, uid, gid)
@@ -333,12 +309,69 @@ func deleteIngressQdisc(link netlink.Link) error {
333309
return nil
334310
}
335311

312+
// discoverContainerIface discovers the container's network interface by
313+
// scanning all links in the current network namespace and returning the first
314+
// non-loopback link that has an IP address and a default route.
315+
func discoverContainerIface() (netlink.Link, error) {
316+
handle, err := netlink.NewHandle()
317+
if err != nil {
318+
return nil, err
319+
}
320+
defer handle.Close()
321+
links, err := handle.LinkList()
322+
if err != nil {
323+
return nil, err
324+
}
325+
for _, link := range links {
326+
attrs := link.Attrs()
327+
if attrs == nil {
328+
netlog.Debug("skipping link with nil attributes")
329+
continue
330+
}
331+
// skip loopback
332+
if (attrs.Flags & net.FlagLoopback) != 0 {
333+
netlog.Debugf("skipping loopback interface %s", attrs.Name)
334+
continue
335+
}
336+
// must have addresses configured
337+
addrs, err := handle.AddrList(link, netlink.FAMILY_ALL)
338+
if err != nil {
339+
netlog.Debugf("skipping interface %s: failed to list addresses: %v", attrs.Name, err)
340+
continue
341+
}
342+
if len(addrs) == 0 {
343+
netlog.Debugf("skipping interface %s: no addresses configured", attrs.Name)
344+
continue
345+
}
346+
// look for a default route on this interface
347+
routes, err := handle.RouteList(link, netlink.FAMILY_ALL)
348+
if err != nil {
349+
netlog.Debugf("skipping interface %s: failed to list routes: %v", attrs.Name, err)
350+
continue
351+
}
352+
for _, r := range routes {
353+
// default route: Dst == nil OR represented as 0.0.0.0/0 or ::/0
354+
if r.Dst == nil {
355+
return link, nil
356+
}
357+
if r.Dst != nil {
358+
dstStr := r.Dst.String()
359+
if dstStr == "0.0.0.0/0" || dstStr == "::/0" {
360+
return link, nil
361+
}
362+
}
363+
}
364+
netlog.Debugf("skipping interface %s: no default route found", attrs.Name)
365+
}
366+
return nil, errors.New("no suitable network interface found in namespace")
367+
}
368+
336369
func deleteAllQDiscs(device netlink.Link) error {
337370
err := deleteIngressQdisc(device)
338371
if err != nil {
339372
return err
340373
}
341-
device, err = netlink.LinkByName(DefaultInterface)
374+
device, err = discoverContainerIface()
342375
if err != nil {
343376
return err
344377
}
@@ -357,8 +390,7 @@ func deleteAllTCFilters(device netlink.Link) error {
357390
return nil
358391
}
359392
allFilters = append(allFilters, tapFilters...)
360-
361-
device, err = netlink.LinkByName(DefaultInterface)
393+
device, err = discoverContainerIface()
362394
if err != nil {
363395
return err
364396
}

‎pkg/network/network_dynamic.go‎

Lines changed: 5 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,6 @@ import (
1818
"fmt"
1919
"strconv"
2020
"strings"
21-
22-
"github.com/vishvananda/netlink"
2321
)
2422

2523
type DynamicNetwork struct {
@@ -43,10 +41,9 @@ func (n DynamicNetwork) NetworkSetup(uid uint32, gid uint32) (*UnikernelNetworkI
4341
return nil, fmt.Errorf("unsupported operation: can't spawn multiple unikernels in the same network namespace")
4442
}
4543

46-
netlog.Debugf("trying LinkByName(%s)", DefaultInterface)
47-
redirectLink, err := netlink.LinkByName(DefaultInterface)
44+
redirectLink, err := discoverContainerIface()
4845
if err != nil {
49-
return nil, fmt.Errorf("failed to find interface %s: %w", DefaultInterface, err)
46+
return nil, fmt.Errorf("failed to find container interface, (unikernel may have been spawned using ctr): %w", err)
5047
}
5148
netlog.Debugf("found interface %s (index=%d)", redirectLink.Attrs().Name, redirectLink.Attrs().Index)
5249

@@ -59,10 +56,10 @@ func (n DynamicNetwork) NetworkSetup(uid uint32, gid uint32) (*UnikernelNetworkI
5956
}
6057
netlog.Debugf("tap device created: %s", newTapDevice.Attrs().Name)
6158

62-
netlog.Debugf("fetching info for %s", DefaultInterface)
63-
ifInfo, err := getInterfaceInfo(DefaultInterface)
59+
netlog.Debugf("fetching info for %s", redirectLink.Attrs().Name)
60+
ifInfo, err := getInterfaceInfo(redirectLink.Attrs().Name)
6461
if err != nil {
65-
return nil, fmt.Errorf("getInterfaceInfo(%s) failed: %w", DefaultInterface, err)
62+
return nil, fmt.Errorf("getInterfaceInfo(%s) failed: %w", redirectLink.Attrs().Name, err)
6663
}
6764

6865
return &UnikernelNetworkInfo{

‎pkg/network/network_static.go‎

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,6 @@ import (
2222
"strings"
2323

2424
"github.com/urunc-dev/urunc/internal/constants"
25-
"github.com/vishvananda/netlink"
2625
)
2726

2827
var StaticIPAddr = fmt.Sprintf("%s/24", constants.StaticNetworkTapIP)
@@ -92,16 +91,16 @@ func setNATRule(iface string, sourceIP string) error {
9291
func (n StaticNetwork) NetworkSetup(uid uint32, gid uint32) (*UnikernelNetworkInfo, error) {
9392
newTapName := strings.ReplaceAll(DefaultTap, "X", "0")
9493
addTCRules := false
95-
redirectLink, err := netlink.LinkByName(DefaultInterface)
94+
redirectLink, err := discoverContainerIface()
9695
if err != nil {
97-
netlog.Errorf("failed to find %s interface", DefaultInterface)
96+
netlog.Errorf("failed to find container interface, (unikernel may have been spawned using ctr): %v", err)
9897
return nil, err
9998
}
10099
newTapDevice, err := networkSetup(newTapName, StaticIPAddr, redirectLink, addTCRules, uid, gid)
101100
if err != nil {
102101
return nil, err
103102
}
104-
err = setNATRule(DefaultInterface, StaticIPAddr)
103+
err = setNATRule(redirectLink.Attrs().Name, StaticIPAddr)
105104
if err != nil {
106105
return nil, err
107106
}
@@ -111,7 +110,7 @@ func (n StaticNetwork) NetworkSetup(uid uint32, gid uint32) (*UnikernelNetworkIn
111110
IP: constants.StaticNetworkUnikernelIP,
112111
DefaultGateway: constants.StaticNetworkTapIP,
113112
Mask: "255.255.255.0",
114-
Interface: DefaultInterface, // or tap0_urunc?
113+
Interface: redirectLink.Attrs().Name, // or tap0_urunc?
115114
MAC: redirectLink.Attrs().HardwareAddr.String(),
116115
},
117116
}, nil

0 commit comments

Comments
 (0)