Skip to content

Commit f6f474b

Browse files
HadrienPattedatadog-compute-robot
authored andcommitted
runtime: Add support for netkit endpoints
Add support for [`netkit`](https://git.kernel.org/pub/scm/linux/kernel/git/bpf/bpf-next.git/commit/?id=22360fad5889cbefe1eca695b0cc0273ab280b56) network devices similarly to how `veth` devices are currently handled. Signed-off-by: Hadrien Patte <hadrien.patte@datadoghq.com>
1 parent 8628519 commit f6f474b

8 files changed

Lines changed: 483 additions & 6 deletions

File tree

src/runtime/virtcontainers/endpoint.go

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,9 @@ const (
5050
// VethEndpointType is the virtual network interface.
5151
VethEndpointType EndpointType = "virtual"
5252

53+
// NetkitEndpointType is the netkit network interface.
54+
NetkitEndpointType EndpointType = "netkit"
55+
5356
// VhostUserEndpointType is the vhostuser network interface.
5457
VhostUserEndpointType EndpointType = "vhost-user"
5558

@@ -85,6 +88,9 @@ func (endpointType *EndpointType) Set(value string) error {
8588
case "virtual":
8689
*endpointType = VethEndpointType
8790
return nil
91+
case "netkit":
92+
*endpointType = NetkitEndpointType
93+
return nil
8894
case "vhost-user":
8995
*endpointType = VhostUserEndpointType
9096
return nil
@@ -118,6 +124,8 @@ func (endpointType *EndpointType) String() string {
118124
return string(PhysicalEndpointType)
119125
case VethEndpointType:
120126
return string(VethEndpointType)
127+
case NetkitEndpointType:
128+
return string(NetkitEndpointType)
121129
case VhostUserEndpointType:
122130
return string(VhostUserEndpointType)
123131
case MacvlanEndpointType:

src/runtime/virtcontainers/endpoint_test.go

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,10 @@ func TestVfioEndpointTypeSet(t *testing.T) {
4646
testEndpointTypeSet(t, "vfio", VfioEndpointType)
4747
}
4848

49+
func TestNetkitEndpointTypeSet(t *testing.T) {
50+
testEndpointTypeSet(t, "netkit", NetkitEndpointType)
51+
}
52+
4953
func TestEndpointTypeSetFailure(t *testing.T) {
5054
var endpointType EndpointType
5155

@@ -82,6 +86,11 @@ func TestMacvtapEndpointTypeString(t *testing.T) {
8286
testEndpointTypeString(t, &endpointType, string(MacvtapEndpointType))
8387
}
8488

89+
func TestNetkitEndpointTypeString(t *testing.T) {
90+
endpointType := NetkitEndpointType
91+
testEndpointTypeString(t, &endpointType, string(NetkitEndpointType))
92+
}
93+
8594
func TestIncorrectEndpointTypeString(t *testing.T) {
8695
var endpointType EndpointType
8796
testEndpointTypeString(t, &endpointType, "")
Lines changed: 216 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,216 @@
1+
//go:build linux
2+
3+
// Copyright (c) 2025 Datadog, Inc
4+
//
5+
// SPDX-License-Identifier: Apache-2.0
6+
//
7+
8+
package virtcontainers
9+
10+
import (
11+
"context"
12+
"fmt"
13+
14+
"github.com/containernetworking/plugins/pkg/ns"
15+
persistapi "github.com/kata-containers/kata-containers/src/runtime/virtcontainers/persist/api"
16+
vcTypes "github.com/kata-containers/kata-containers/src/runtime/virtcontainers/types"
17+
)
18+
19+
var netkitTrace = getNetworkTrace(NetkitEndpointType)
20+
21+
// NetkitEndpoint gathers a network pair and its properties.
22+
type NetkitEndpoint struct {
23+
EndpointType EndpointType
24+
PCIPath vcTypes.PciPath
25+
CCWDevice *vcTypes.CcwDevice
26+
EndpointProperties NetworkInfo
27+
NetPair NetworkInterfacePair
28+
RxRateLimiter bool
29+
TxRateLimiter bool
30+
}
31+
32+
func createNetkitNetworkEndpoint(idx int, ifName string, interworkingModel NetInterworkingModel) (*NetkitEndpoint, error) {
33+
if idx < 0 {
34+
return &NetkitEndpoint{}, fmt.Errorf("invalid network endpoint index: %d", idx)
35+
}
36+
37+
netPair, err := createNetworkInterfacePair(idx, ifName, interworkingModel)
38+
if err != nil {
39+
return nil, err
40+
}
41+
42+
endpoint := &NetkitEndpoint{
43+
// TODO This is too specific. We may need to create multiple
44+
// end point types here and then decide how to connect them
45+
// at the time of hypervisor attach and not here
46+
NetPair: netPair,
47+
EndpointType: NetkitEndpointType,
48+
}
49+
if ifName != "" {
50+
endpoint.NetPair.VirtIface.Name = ifName
51+
}
52+
53+
return endpoint, nil
54+
}
55+
56+
// Properties returns properties for the netkit interface in the network pair.
57+
func (endpoint *NetkitEndpoint) Properties() NetworkInfo {
58+
return endpoint.EndpointProperties
59+
}
60+
61+
// Name returns name of the netkit interface in the network pair.
62+
func (endpoint *NetkitEndpoint) Name() string {
63+
return endpoint.NetPair.VirtIface.Name
64+
}
65+
66+
// HardwareAddr returns the mac address that is assigned to the tap interface
67+
// in th network pair.
68+
func (endpoint *NetkitEndpoint) HardwareAddr() string {
69+
return endpoint.NetPair.TAPIface.HardAddr
70+
}
71+
72+
// Type identifies the endpoint as a netkit endpoint.
73+
func (endpoint *NetkitEndpoint) Type() EndpointType {
74+
return endpoint.EndpointType
75+
}
76+
77+
// PciPath returns the PCI path of the endpoint.
78+
func (endpoint *NetkitEndpoint) PciPath() vcTypes.PciPath {
79+
return endpoint.PCIPath
80+
}
81+
82+
// SetPciPath sets the PCI path of the endpoint.
83+
func (endpoint *NetkitEndpoint) SetPciPath(pciPath vcTypes.PciPath) {
84+
endpoint.PCIPath = pciPath
85+
}
86+
87+
// CcwDevice returns the CCW device of the endpoint.
88+
func (endpoint *NetkitEndpoint) CcwDevice() *vcTypes.CcwDevice {
89+
return endpoint.CCWDevice
90+
}
91+
92+
// SetCcwDevice sets the CCW device of the endpoint.
93+
func (endpoint *NetkitEndpoint) SetCcwDevice(ccwDev vcTypes.CcwDevice) {
94+
endpoint.CCWDevice = &ccwDev
95+
}
96+
97+
// NetworkPair returns the network pair of the endpoint.
98+
func (endpoint *NetkitEndpoint) NetworkPair() *NetworkInterfacePair {
99+
return &endpoint.NetPair
100+
}
101+
102+
// SetProperties sets the properties for the endpoint.
103+
func (endpoint *NetkitEndpoint) SetProperties(properties NetworkInfo) {
104+
endpoint.EndpointProperties = properties
105+
}
106+
107+
// Attach for netkit endpoint bridges the network pair and adds the
108+
// tap interface of the network pair to the hypervisor.
109+
func (endpoint *NetkitEndpoint) Attach(ctx context.Context, s *Sandbox) error {
110+
span, ctx := netkitTrace(ctx, "Attach", endpoint)
111+
defer span.End()
112+
113+
h := s.hypervisor
114+
if err := xConnectVMNetwork(ctx, endpoint, h); err != nil {
115+
networkLogger().WithError(err).Error("Error bridging netkit endpoint")
116+
return err
117+
}
118+
119+
return h.AddDevice(ctx, endpoint, NetDev)
120+
}
121+
122+
// Detach for the netkit endpoint tears down the tap and bridge
123+
// created for the netkit interface.
124+
func (endpoint *NetkitEndpoint) Detach(ctx context.Context, netNsCreated bool, netNsPath string) error {
125+
// The network namespace would have been deleted at this point
126+
// if it has not been created by virtcontainers.
127+
if !netNsCreated {
128+
return nil
129+
}
130+
131+
span, ctx := netkitTrace(ctx, "Detach", endpoint)
132+
defer span.End()
133+
134+
return doNetNS(netNsPath, func(_ ns.NetNS) error {
135+
return xDisconnectVMNetwork(ctx, endpoint)
136+
})
137+
}
138+
139+
// HotAttach for the netkit endpoint uses hot plug device
140+
func (endpoint *NetkitEndpoint) HotAttach(ctx context.Context, s *Sandbox) error {
141+
span, ctx := netkitTrace(ctx, "HotAttach", endpoint)
142+
defer span.End()
143+
144+
h := s.hypervisor
145+
if err := xConnectVMNetwork(ctx, endpoint, h); err != nil {
146+
networkLogger().WithError(err).Error("Error bridging netkit ep")
147+
return err
148+
}
149+
150+
if _, err := h.HotplugAddDevice(ctx, endpoint, NetDev); err != nil {
151+
networkLogger().WithError(err).Error("Error attach netkit ep")
152+
return err
153+
}
154+
return nil
155+
}
156+
157+
// HotDetach for the netkit endpoint uses hot pull device
158+
func (endpoint *NetkitEndpoint) HotDetach(ctx context.Context, s *Sandbox, netNsCreated bool, netNsPath string) error {
159+
if !netNsCreated {
160+
return nil
161+
}
162+
163+
span, ctx := netkitTrace(ctx, "HotDetach", endpoint)
164+
defer span.End()
165+
166+
if err := doNetNS(netNsPath, func(_ ns.NetNS) error {
167+
return xDisconnectVMNetwork(ctx, endpoint)
168+
}); err != nil {
169+
networkLogger().WithError(err).Warn("Error un-bridging netkit ep")
170+
}
171+
172+
h := s.hypervisor
173+
if _, err := h.HotplugRemoveDevice(ctx, endpoint, NetDev); err != nil {
174+
networkLogger().WithError(err).Error("Error detach netkit ep")
175+
return err
176+
}
177+
return nil
178+
}
179+
180+
func (endpoint *NetkitEndpoint) save() persistapi.NetworkEndpoint {
181+
netpair := saveNetIfPair(&endpoint.NetPair)
182+
183+
return persistapi.NetworkEndpoint{
184+
Type: string(endpoint.Type()),
185+
Netkit: &persistapi.NetkitEndpoint{
186+
NetPair: *netpair,
187+
},
188+
}
189+
}
190+
191+
func (endpoint *NetkitEndpoint) load(s persistapi.NetworkEndpoint) {
192+
endpoint.EndpointType = NetkitEndpointType
193+
194+
if s.Netkit != nil {
195+
netpair := loadNetIfPair(&s.Netkit.NetPair)
196+
endpoint.NetPair = *netpair
197+
}
198+
}
199+
200+
func (endpoint *NetkitEndpoint) GetRxRateLimiter() bool {
201+
return endpoint.RxRateLimiter
202+
}
203+
204+
func (endpoint *NetkitEndpoint) SetRxRateLimiter() error {
205+
endpoint.RxRateLimiter = true
206+
return nil
207+
}
208+
209+
func (endpoint *NetkitEndpoint) GetTxRateLimiter() bool {
210+
return endpoint.TxRateLimiter
211+
}
212+
213+
func (endpoint *NetkitEndpoint) SetTxRateLimiter() error {
214+
endpoint.TxRateLimiter = true
215+
return nil
216+
}

0 commit comments

Comments
 (0)