@@ -25,6 +25,7 @@ const (
2525 UpdateTypeLink NetlinkUpdateType = "link"
2626 UpdateTypeAddr NetlinkUpdateType = "addr"
2727 UpdateTypeRoute NetlinkUpdateType = "route"
28+ fakeBridge string = "runv0"
2829)
2930
3031// NetlinkUpdate tracks the change of network namespace.
@@ -53,71 +54,22 @@ type nsListener struct {
5354 cmd * exec.Cmd
5455}
5556
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+ }
10761
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 )
11369 }
114-
115- glog .V (3 ).Infof ("find bridge %s" , bridge .Name )
116-
117- return bridge .Name , options , nil
11870}
11971
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 {
12173 /* send collect netns request to nsListener */
12274 if err := enc .Encode ("init" ); err != nil {
12375 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
14698 }
14799 }
148100
101+ createFakeBridge ()
102+
149103 glog .V (3 ).Infof ("interface configuration for sandbox ns is %#v" , infos )
104+ mirredPairs := []tcMirredPair {}
150105 for _ , info := range infos {
151- bridge , options , err := GetBridgeFromIndex (info .PeerIndex )
152- if err != nil {
153- glog .Error (err )
154- continue
155- }
156-
157106 nicId := strconv .Itoa (info .Index )
158107
159108 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 ,
165113 }
166114
167115 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
172120 // which would not be the proper way to name device name, instead it
173121 // should be the same as what we specified in the network namespace.
174122 //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 )
176130 if err != nil {
177131 glog .Error (err )
178132 return err
179133 }
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 })
180139 }
181140
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 {
184147 glog .Error (err )
185148 return err
186149 }
@@ -243,18 +206,11 @@ func nsListenerStrap(vm *hypervisor.Vm, enc *gob.Encoder, dec *gob.Decoder) {
243206 continue
244207 }
245208
246- bridge , options , err := GetBridgeFromIndex (link .Attrs ().ParentIndex )
247- if err != nil {
248- glog .Error (err )
249- continue
250- }
251-
252209 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 (),
258214 }
259215
260216 err = vm .AddNic (inf )
@@ -336,7 +292,7 @@ func startNsListener(options runvOptions, vm *hypervisor.Vm) (err error) {
336292 return err
337293 }
338294
339- initSandboxNetwork (vm , enc , dec )
295+ initSandboxNetwork (vm , enc , dec , cmd . Process . Pid )
340296 glog .V (1 ).Infof ("nsListener pid is %d" , cmd .Process .Pid )
341297 return nil
342298}
@@ -388,12 +344,17 @@ func doListen() {
388344
389345 /* send interface info to `runv create` */
390346 infos := collectionInterfaceInfo ()
391- if err : = enc .Encode (infos ); err != nil {
347+ if err = enc .Encode (infos ); err != nil {
392348 glog .Error (err )
393349 return
394350 }
395351
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 {
397358 glog .Error (err )
398359 return
399360 }
@@ -423,29 +384,79 @@ func collectionInterfaceInfo() []InterfaceInfo {
423384 // lo is here too
424385 continue
425386 }
426-
387+ info := InterfaceInfo {
388+ Index : link .Attrs ().Index ,
389+ PeerIndex : link .Attrs ().ParentIndex ,
390+ }
391+ ipAddrs := []string {}
427392 addrs , err := netlink .AddrList (link , netlink .FAMILY_V4 )
428393 if err != nil {
429394 glog .Error (err )
430395 return infos
431396 }
432397
433398 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 ())
441400 }
401+ info .Ip = strings .Join (ipAddrs , "," )
402+ glog .Infof ("get interface %v" , info )
403+ infos = append (infos , info )
442404
443- // set link down, tap device take over it
444- netlink .LinkSetDown (link )
445405 }
446406 return infos
447407}
448408
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+
449460// This function should be put into the main process or somewhere that can be
450461// use to init the network namespace trap.
451462func setupNetworkNsTrap (netNs2Containerd func (NetlinkUpdate )) {
0 commit comments