@@ -25,6 +25,7 @@ const (
25
25
UpdateTypeLink NetlinkUpdateType = "link"
26
26
UpdateTypeAddr NetlinkUpdateType = "addr"
27
27
UpdateTypeRoute NetlinkUpdateType = "route"
28
+ fakeBridge string = "runv0"
28
29
)
29
30
30
31
// NetlinkUpdate tracks the change of network namespace.
@@ -53,71 +54,22 @@ type nsListener struct {
53
54
cmd * exec.Cmd
54
55
}
55
56
56
- func GetBridgeFromIndex (idx int ) (string , string , error ) {
57
- var attr , bridge * netlink.LinkAttrs
58
- var options string
59
-
60
- links , err := netlink .LinkList ()
61
- if err != nil {
62
- glog .Error (err )
63
- return "" , "" , err
64
- }
65
-
66
- for _ , link := range links {
67
- if link .Type () != "veth" {
68
- continue
69
- }
70
-
71
- if link .Attrs ().Index == idx {
72
- attr = link .Attrs ()
73
- break
74
- }
75
- }
76
-
77
- if attr == nil {
78
- return "" , "" , fmt .Errorf ("cann't find nic whose ifindex is %d" , idx )
79
- }
80
-
81
- for _ , link := range links {
82
- if link .Type () != "bridge" && link .Type () != "openvswitch" {
83
- continue
84
- }
85
-
86
- if link .Attrs ().Index == attr .MasterIndex {
87
- bridge = link .Attrs ()
88
- break
89
- }
90
- }
91
-
92
- if bridge == nil {
93
- return "" , "" , fmt .Errorf ("cann't find bridge contains nic whose ifindex is %d" , idx )
94
- }
95
-
96
- if bridge .Name == "ovs-system" {
97
- veth , err := netlink .LinkByIndex (idx )
98
- if err != nil {
99
- return "" , "" , err
100
- }
101
-
102
- out , err := exec .Command ("ovs-vsctl" , "port-to-br" , veth .Attrs ().Name ).CombinedOutput ()
103
- if err != nil {
104
- return "" , "" , err
105
- }
106
- bridge .Name = strings .TrimSpace (string (out ))
57
+ type tcMirredPair struct {
58
+ NsIfIndex int
59
+ HostIfIndex int
60
+ }
107
61
108
- out , err = exec .Command ("ovs-vsctl" , "get" , "port" , veth .Attrs ().Name , "tag" ).CombinedOutput ()
109
- if err != nil {
110
- return "" , "" , err
111
- }
112
- options = "tag=" + strings .TrimSpace (string (out ))
62
+ func createFakeBridge () {
63
+ // add an useless bridge to satisfy hypervisor, most of them need to join bridge.
64
+ la := netlink .NewLinkAttrs ()
65
+ la .Name = fakeBridge
66
+ bridge := & netlink.Bridge {LinkAttrs : la }
67
+ if err := netlink .LinkAdd (bridge ); err != nil && ! os .IsExist (err ) {
68
+ glog .Warningf ("fail to create fake bridge: %v, %v" , fakeBridge , err )
113
69
}
114
-
115
- glog .V (3 ).Infof ("find bridge %s" , bridge .Name )
116
-
117
- return bridge .Name , options , nil
118
70
}
119
71
120
- func initSandboxNetwork (vm * hypervisor.Vm , enc * gob.Encoder , dec * gob.Decoder ) error {
72
+ func initSandboxNetwork (vm * hypervisor.Vm , enc * gob.Encoder , dec * gob.Decoder , pid int ) error {
121
73
/* send collect netns request to nsListener */
122
74
if err := enc .Encode ("init" ); err != nil {
123
75
glog .Errorf ("listener.dec.Decode init error: %v" , err )
@@ -146,22 +98,18 @@ func initSandboxNetwork(vm *hypervisor.Vm, enc *gob.Encoder, dec *gob.Decoder) e
146
98
}
147
99
}
148
100
101
+ createFakeBridge ()
102
+
149
103
glog .V (3 ).Infof ("interface configuration for sandbox ns is %#v" , infos )
104
+ mirredPairs := []tcMirredPair {}
150
105
for _ , info := range infos {
151
- bridge , options , err := GetBridgeFromIndex (info .PeerIndex )
152
- if err != nil {
153
- glog .Error (err )
154
- continue
155
- }
156
-
157
106
nicId := strconv .Itoa (info .Index )
158
107
159
108
conf := & api.InterfaceDescription {
160
- Id : nicId , //ip as an id
161
- Lo : false ,
162
- Bridge : bridge ,
163
- Ip : info .Ip ,
164
- Options : options ,
109
+ Id : nicId , //ip as an id
110
+ Lo : false ,
111
+ Bridge : fakeBridge ,
112
+ Ip : info .Ip ,
165
113
}
166
114
167
115
if gw_route != nil && gw_route .LinkIndex == info .Index {
@@ -172,15 +120,30 @@ func initSandboxNetwork(vm *hypervisor.Vm, enc *gob.Encoder, dec *gob.Decoder) e
172
120
// which would not be the proper way to name device name, instead it
173
121
// should be the same as what we specified in the network namespace.
174
122
//err = hp.vm.AddNic(info.Index, fmt.Sprintf("eth%d", idx), conf)
175
- err = vm .AddNic (conf )
123
+ if err = vm .AddNic (conf ); err != nil {
124
+ glog .Error (err )
125
+ return err
126
+ }
127
+
128
+ // move device into container-shim netns
129
+ hostLink , err := netlink .LinkByName (conf .TapName )
176
130
if err != nil {
177
131
glog .Error (err )
178
132
return err
179
133
}
134
+ if err = netlink .LinkSetNsPid (hostLink , pid ); err != nil {
135
+ glog .Error (err )
136
+ return err
137
+ }
138
+ mirredPairs = append (mirredPairs , tcMirredPair {info .Index , hostLink .Attrs ().Index })
180
139
}
181
140
182
- err = vm .AddRoute ()
183
- if err != nil {
141
+ if err = enc .Encode (mirredPairs ); err != nil {
142
+ glog .Error (err )
143
+ return err
144
+ }
145
+
146
+ if err = vm .AddRoute (); err != nil {
184
147
glog .Error (err )
185
148
return err
186
149
}
@@ -243,18 +206,11 @@ func nsListenerStrap(vm *hypervisor.Vm, enc *gob.Encoder, dec *gob.Decoder) {
243
206
continue
244
207
}
245
208
246
- bridge , options , err := GetBridgeFromIndex (link .Attrs ().ParentIndex )
247
- if err != nil {
248
- glog .Error (err )
249
- continue
250
- }
251
-
252
209
inf := & api.InterfaceDescription {
253
- Id : strconv .Itoa (link .Attrs ().Index ),
254
- Lo : false ,
255
- Bridge : bridge ,
256
- Ip : update .Addr .LinkAddress .String (),
257
- Options : options ,
210
+ Id : strconv .Itoa (link .Attrs ().Index ),
211
+ Lo : false ,
212
+ Bridge : fakeBridge ,
213
+ Ip : update .Addr .LinkAddress .String (),
258
214
}
259
215
260
216
err = vm .AddNic (inf )
@@ -336,7 +292,7 @@ func startNsListener(options runvOptions, vm *hypervisor.Vm) (err error) {
336
292
return err
337
293
}
338
294
339
- initSandboxNetwork (vm , enc , dec )
295
+ initSandboxNetwork (vm , enc , dec , cmd . Process . Pid )
340
296
glog .V (1 ).Infof ("nsListener pid is %d" , cmd .Process .Pid )
341
297
return nil
342
298
}
@@ -388,12 +344,17 @@ func doListen() {
388
344
389
345
/* send interface info to `runv create` */
390
346
infos := collectionInterfaceInfo ()
391
- if err : = enc .Encode (infos ); err != nil {
347
+ if err = enc .Encode (infos ); err != nil {
392
348
glog .Error (err )
393
349
return
394
350
}
395
351
396
- if err := enc .Encode (routes ); err != nil {
352
+ if err = enc .Encode (routes ); err != nil {
353
+ glog .Error (err )
354
+ return
355
+ }
356
+
357
+ if err = setupTcMirredRule (dec ); err != nil {
397
358
glog .Error (err )
398
359
return
399
360
}
@@ -423,29 +384,79 @@ func collectionInterfaceInfo() []InterfaceInfo {
423
384
// lo is here too
424
385
continue
425
386
}
426
-
387
+ info := InterfaceInfo {
388
+ Index : link .Attrs ().Index ,
389
+ PeerIndex : link .Attrs ().ParentIndex ,
390
+ }
391
+ ipAddrs := []string {}
427
392
addrs , err := netlink .AddrList (link , netlink .FAMILY_V4 )
428
393
if err != nil {
429
394
glog .Error (err )
430
395
return infos
431
396
}
432
397
433
398
for _ , addr := range addrs {
434
- info := InterfaceInfo {
435
- Ip : addr .IPNet .String (),
436
- Index : link .Attrs ().Index ,
437
- PeerIndex : link .Attrs ().ParentIndex ,
438
- }
439
- glog .Infof ("get interface %v" , info )
440
- infos = append (infos , info )
399
+ ipAddrs = append (ipAddrs , addr .IPNet .String ())
441
400
}
401
+ info .Ip = strings .Join (ipAddrs , "," )
402
+ glog .Infof ("get interface %v" , info )
403
+ infos = append (infos , info )
442
404
443
- // set link down, tap device take over it
444
- netlink .LinkSetDown (link )
445
405
}
446
406
return infos
447
407
}
448
408
409
+ func setupTcMirredRule (dec * gob.Decoder ) error {
410
+ mirredPairs := []tcMirredPair {}
411
+ dec .Decode (& mirredPairs )
412
+
413
+ glog .Infof ("got mirredPairs: %v" , mirredPairs )
414
+ for _ , pair := range mirredPairs {
415
+ hostLink , err := netlink .LinkByIndex (pair .HostIfIndex )
416
+ if err != nil {
417
+ return err
418
+ }
419
+ if err = netlink .LinkSetUp (hostLink ); err != nil {
420
+ return err
421
+ }
422
+
423
+ qdisc := & netlink.Ingress {
424
+ QdiscAttrs : netlink.QdiscAttrs {
425
+ LinkIndex : pair .NsIfIndex ,
426
+ Parent : netlink .HANDLE_INGRESS ,
427
+ Handle : netlink .MakeHandle (0xffff , 0 ),
428
+ },
429
+ }
430
+ if err = netlink .QdiscAdd (qdisc ); err != nil {
431
+ return err
432
+ }
433
+ filter := & netlink.U32 {
434
+ FilterAttrs : netlink.FilterAttrs {
435
+ LinkIndex : pair .NsIfIndex ,
436
+ Parent : qdisc .Handle ,
437
+ Priority : 1 ,
438
+ Protocol : syscall .ETH_P_ALL ,
439
+ },
440
+ RedirIndex : pair .HostIfIndex ,
441
+ ClassId : netlink .MakeHandle (1 , 1 ),
442
+ }
443
+ if err = netlink .FilterAdd (filter ); err != nil {
444
+ return err
445
+ }
446
+
447
+ qdisc .QdiscAttrs .LinkIndex = pair .HostIfIndex
448
+ if err = netlink .QdiscAdd (qdisc ); err != nil {
449
+ return err
450
+ }
451
+ filter .FilterAttrs .LinkIndex = pair .HostIfIndex
452
+ filter .RedirIndex = pair .NsIfIndex
453
+ if err = netlink .FilterAdd (filter ); err != nil {
454
+ return err
455
+ }
456
+ }
457
+ return nil
458
+ }
459
+
449
460
// This function should be put into the main process or somewhere that can be
450
461
// use to init the network namespace trap.
451
462
func setupNetworkNsTrap (netNs2Containerd func (NetlinkUpdate )) {
0 commit comments