@@ -20,21 +20,16 @@ import (
20
20
"fmt"
21
21
22
22
"github.com/vishvananda/netlink"
23
+ "github.com/vishvananda/netlink/nl"
23
24
"github.com/vishvananda/netns"
25
+ "golang.org/x/sys/unix"
24
26
)
25
27
26
28
func nsAttachNetdev (hostIfName string , containerNsPAth string , ifName string ) error {
27
29
hostDev , err := netlink .LinkByName (hostIfName )
28
30
if err != nil {
29
31
return err
30
32
}
31
- attrs := netlink .NewLinkAttrs ()
32
- attrs .Index = hostDev .Attrs ().Index
33
- attrs .MTU = hostDev .Attrs ().MTU
34
- attrs .HardwareAddr = hostDev .Attrs ().HardwareAddr
35
- attrs .Name = ifName
36
- // Store the original name
37
- attrs .Alias = hostIfName
38
33
39
34
// Devices can be renamed only when down
40
35
if err = netlink .LinkSetDown (hostDev ); err != nil {
@@ -45,15 +40,46 @@ func nsAttachNetdev(hostIfName string, containerNsPAth string, ifName string) er
45
40
if err != nil {
46
41
return err
47
42
}
48
- attrs .Namespace = netlink .NsFd (containerNs )
49
43
50
- dev := & netlink.Device {
51
- LinkAttrs : attrs ,
44
+ attrs := hostDev .Attrs ()
45
+ // Store the original name
46
+ attrs .Alias = hostIfName
47
+
48
+ // copy from netlink.LinkModify(dev) using only the parts needed
49
+ flags := unix .NLM_F_REQUEST | unix .NLM_F_ACK
50
+ req := nl .NewNetlinkRequest (unix .RTM_NEWLINK , flags )
51
+ // Get a netlink socket in current namespace
52
+ s , err := nl .GetNetlinkSocketAt (netns .None (), netns .None (), unix .NETLINK_ROUTE )
53
+ if err != nil {
54
+ return fmt .Errorf ("could not get network namespace handle: %w" , err )
52
55
}
56
+ req .Sockets = map [int ]* nl.SocketHandle {
57
+ unix .NETLINK_ROUTE : {Socket : s },
58
+ }
59
+
60
+ msg := nl .NewIfInfomsg (unix .AF_UNSPEC )
61
+ msg .Index = int32 (attrs .Index )
62
+ req .AddData (msg )
63
+
64
+ nameData := nl .NewRtAttr (unix .IFLA_IFNAME , nl .ZeroTerminated (attrs .Name ))
65
+ req .AddData (nameData )
66
+
67
+ alias := nl .NewRtAttr (unix .IFLA_IFALIAS , []byte (attrs .Alias ))
68
+ req .AddData (alias )
69
+
70
+ mtu := nl .NewRtAttr (unix .IFLA_MTU , nl .Uint32Attr (uint32 (attrs .MTU )))
71
+ req .AddData (mtu )
72
+
73
+ val := nl .Uint32Attr (uint32 (containerNs ))
74
+ attr := nl .NewRtAttr (unix .IFLA_NET_NS_FD , val )
75
+ req .AddData (attr )
53
76
54
- err = netlink .LinkModify (dev )
77
+ linkInfo := nl .NewRtAttr (unix .IFLA_LINKINFO , nil )
78
+ linkInfo .AddRtAttr (nl .IFLA_INFO_KIND , nil )
79
+
80
+ _ , err = req .Execute (unix .NETLINK_ROUTE , 0 )
55
81
if err != nil {
56
- return fmt . Errorf ( "could not modify network device %s : %w" , hostIfName , err )
82
+ return err
57
83
}
58
84
59
85
// to avoid golang problem with goroutines we create the socket in the
@@ -63,9 +89,9 @@ func nsAttachNetdev(hostIfName string, containerNsPAth string, ifName string) er
63
89
return err
64
90
}
65
91
66
- nsLink , err := nhNs .LinkByName (dev .Name )
92
+ nsLink , err := nhNs .LinkByName (attrs .Name )
67
93
if err != nil {
68
- return fmt .Errorf ("link not found for interface %s on namespace %s: %w" , dev .Name , containerNsPAth , err )
94
+ return fmt .Errorf ("link not found for interface %s on namespace %s: %w" , attrs .Name , containerNsPAth , err )
69
95
}
70
96
71
97
err = nhNs .LinkSetUp (nsLink )
@@ -100,9 +126,7 @@ func nsDetachNetdev(containerNsPAth string, devName string) error {
100
126
return err
101
127
}
102
128
103
- attrs := netlink .NewLinkAttrs ()
104
- attrs .Index = nsLink .Attrs ().Index
105
- attrs .Name = devName
129
+ attrs := nsLink .Attrs ()
106
130
// restore the original name if it was renamed
107
131
if nsLink .Attrs ().Alias != "" {
108
132
attrs .Name = nsLink .Attrs ().Alias
@@ -114,15 +138,40 @@ func nsDetachNetdev(containerNsPAth string, devName string) error {
114
138
}
115
139
defer rootNs .Close ()
116
140
117
- attrs .Namespace = netlink .NsFd (rootNs )
118
-
119
- dev := & netlink.Device {
120
- LinkAttrs : attrs ,
141
+ s , err := nl .GetNetlinkSocketAt (containerNs , rootNs , unix .NETLINK_ROUTE )
142
+ if err != nil {
143
+ return fmt .Errorf ("could not get network namespace handle: %w" , err )
144
+ }
145
+ // copy from netlink.LinkModify(dev) using only the parts needed
146
+ flags := unix .NLM_F_REQUEST | unix .NLM_F_ACK
147
+ req := nl .NewNetlinkRequest (unix .RTM_NEWLINK , flags )
148
+ req .Sockets = map [int ]* nl.SocketHandle {
149
+ unix .NETLINK_ROUTE : {Socket : s },
121
150
}
151
+ msg := nl .NewIfInfomsg (unix .AF_UNSPEC )
152
+ msg .Index = int32 (attrs .Index )
153
+ req .AddData (msg )
154
+
155
+ nameData := nl .NewRtAttr (unix .IFLA_IFNAME , nl .ZeroTerminated (attrs .Name ))
156
+ req .AddData (nameData )
122
157
123
- err = netlink .LinkModify (dev )
158
+ alias := nl .NewRtAttr (unix .IFLA_IFALIAS , []byte (attrs .Alias ))
159
+ req .AddData (alias )
160
+
161
+ mtu := nl .NewRtAttr (unix .IFLA_MTU , nl .Uint32Attr (uint32 (attrs .MTU )))
162
+ req .AddData (mtu )
163
+
164
+ val := nl .Uint32Attr (uint32 (rootNs ))
165
+ attr := nl .NewRtAttr (unix .IFLA_NET_NS_FD , val )
166
+ req .AddData (attr )
167
+
168
+ linkInfo := nl .NewRtAttr (unix .IFLA_LINKINFO , nil )
169
+ linkInfo .AddRtAttr (nl .IFLA_INFO_KIND , nil )
170
+
171
+ _ , err = req .Execute (unix .NETLINK_ROUTE , 0 )
124
172
if err != nil {
125
- return fmt . Errorf ( "could not modify network device %s : %w" , devName , err )
173
+ return err
126
174
}
175
+
127
176
return nil
128
177
}
0 commit comments