Skip to content
This repository was archived by the owner on Feb 8, 2021. It is now read-only.
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit c9df6ab

Browse files
authoredSep 8, 2017
Merge pull request #592 from gao-feng/networktc
use tc mirred rule to connect hypervisor nic and container nic
2 parents 83a4658 + a554624 commit c9df6ab

File tree

21 files changed

+323
-293
lines changed

21 files changed

+323
-293
lines changed
 

‎cli/network.go

Lines changed: 110 additions & 99 deletions
Original file line numberDiff line numberDiff line change
@@ -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.
451462
func setupNetworkNsTrap(netNs2Containerd func(NetlinkUpdate)) {
There was a problem loading the remainder of the diff.

0 commit comments

Comments
 (0)
This repository has been archived.