cr: add network support
We need to enumirate all veth devices on restore and handle {un,}lock-network notifications. Signed-off-by: Andrey Vagin <avagin@openvz.org>
This commit is contained in:
parent
032aca342e
commit
eaa35f552e
|
@ -417,6 +417,18 @@ func (c *linuxContainer) Restore(process *Process, imagePath string) error {
|
|||
req.Opts.ExtMnt = append(req.Opts.ExtMnt, extMnt)
|
||||
}
|
||||
}
|
||||
for _, iface := range c.config.Networks {
|
||||
switch iface.Type {
|
||||
case "veth":
|
||||
veth := new(criurpc.CriuVethPair)
|
||||
veth.IfOut = proto.String(iface.HostInterfaceName)
|
||||
veth.IfIn = proto.String(iface.Name)
|
||||
req.Opts.Veths = append(req.Opts.Veths, veth)
|
||||
break
|
||||
case "loopback":
|
||||
break
|
||||
}
|
||||
}
|
||||
// Pipes that were previously set up for std{in,out,err}
|
||||
// were removed after checkpoint. Use the new ones.
|
||||
var i int32
|
||||
|
@ -555,6 +567,34 @@ func (c *linuxContainer) criuSwrk(process *Process, req *criurpc.CriuReq, imageP
|
|||
return nil
|
||||
}
|
||||
|
||||
// block any external network activity
|
||||
func lockNetwork(config *configs.Config) error {
|
||||
for _, config := range config.Networks {
|
||||
strategy, err := getStrategy(config.Type)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := strategy.detach(config); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func unlockNetwork(config *configs.Config) error {
|
||||
for _, config := range config.Networks {
|
||||
strategy, err := getStrategy(config.Type)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err = strategy.attach(config); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *linuxContainer) criuNotifications(resp *criurpc.CriuResp, process *Process, imagePath string) error {
|
||||
notify := resp.GetNotify()
|
||||
if notify == nil {
|
||||
|
@ -570,6 +610,18 @@ func (c *linuxContainer) criuNotifications(resp *criurpc.CriuResp, process *Proc
|
|||
f.Close()
|
||||
break
|
||||
|
||||
case notify.GetScript() == "network-unlock":
|
||||
if err := unlockNetwork(c.config); err != nil {
|
||||
return err
|
||||
}
|
||||
break
|
||||
|
||||
case notify.GetScript() == "network-lock":
|
||||
if err := lockNetwork(c.config); err != nil {
|
||||
return err
|
||||
}
|
||||
break
|
||||
|
||||
case notify.GetScript() == "post-restore":
|
||||
pid := notify.GetPid()
|
||||
r, err := newRestoredProcess(int(pid))
|
||||
|
|
|
@ -27,6 +27,7 @@ const (
|
|||
SIOC_BRADDBR = 0x89a0
|
||||
SIOC_BRDELBR = 0x89a1
|
||||
SIOC_BRADDIF = 0x89a2
|
||||
SIOC_BRDELIF = 0x89a3
|
||||
)
|
||||
|
||||
const (
|
||||
|
@ -1191,9 +1192,7 @@ func DeleteBridge(name string) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
// Add a slave to abridge device. This is more backward-compatible than
|
||||
// netlink.NetworkSetMaster and works on RHEL 6.
|
||||
func AddToBridge(iface, master *net.Interface) error {
|
||||
func ifIoctBridge(iface, master *net.Interface, op uintptr) error {
|
||||
if len(master.Name) >= IFNAMSIZ {
|
||||
return fmt.Errorf("Interface name %s too long", master.Name)
|
||||
}
|
||||
|
@ -1208,13 +1207,25 @@ func AddToBridge(iface, master *net.Interface) error {
|
|||
copy(ifr.IfrnName[:len(ifr.IfrnName)-1], master.Name)
|
||||
ifr.IfruIndex = int32(iface.Index)
|
||||
|
||||
if _, _, err := syscall.Syscall(syscall.SYS_IOCTL, uintptr(s), SIOC_BRADDIF, uintptr(unsafe.Pointer(&ifr))); err != 0 {
|
||||
if _, _, err := syscall.Syscall(syscall.SYS_IOCTL, uintptr(s), op, uintptr(unsafe.Pointer(&ifr))); err != 0 {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Add a slave to a bridge device. This is more backward-compatible than
|
||||
// netlink.NetworkSetMaster and works on RHEL 6.
|
||||
func AddToBridge(iface, master *net.Interface) error {
|
||||
return ifIoctBridge(iface, master, SIOC_BRADDIF)
|
||||
}
|
||||
|
||||
// Detach a slave from a bridge device. This is more backward-compatible than
|
||||
// netlink.NetworkSetMaster and works on RHEL 6.
|
||||
func DelFromBridge(iface, master *net.Interface) error {
|
||||
return ifIoctBridge(iface, master, SIOC_BRDELIF)
|
||||
}
|
||||
|
||||
func randMacAddr() string {
|
||||
hw := make(net.HardwareAddr, 6)
|
||||
for i := 0; i < 6; i++ {
|
||||
|
|
|
@ -10,6 +10,7 @@ import (
|
|||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/docker/libcontainer/configs"
|
||||
"github.com/docker/libcontainer/netlink"
|
||||
"github.com/docker/libcontainer/utils"
|
||||
)
|
||||
|
@ -24,6 +25,8 @@ var strategies = map[string]networkStrategy{
|
|||
type networkStrategy interface {
|
||||
create(*network, int) error
|
||||
initialize(*network) error
|
||||
detach(*configs.Network) error
|
||||
attach(*configs.Network) error
|
||||
}
|
||||
|
||||
// getStrategy returns the specific network strategy for the
|
||||
|
@ -97,32 +100,39 @@ func (l *loopback) initialize(config *network) error {
|
|||
return netlink.NetworkLinkUp(iface)
|
||||
}
|
||||
|
||||
func (l *loopback) attach(n *configs.Network) (err error) {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (l *loopback) detach(n *configs.Network) (err error) {
|
||||
return nil
|
||||
}
|
||||
|
||||
// veth is a network strategy that uses a bridge and creates
|
||||
// a veth pair, one that is attached to the bridge on the host and the other
|
||||
// is placed inside the container's namespace
|
||||
type veth struct {
|
||||
}
|
||||
|
||||
func (v *veth) create(n *network, nspid int) (err error) {
|
||||
tmpName, err := v.generateTempPeerName()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
n.TempVethPeerName = tmpName
|
||||
defer func() {
|
||||
if err != nil {
|
||||
netlink.NetworkLinkDel(n.HostInterfaceName)
|
||||
netlink.NetworkLinkDel(n.TempVethPeerName)
|
||||
}
|
||||
}()
|
||||
if n.Bridge == "" {
|
||||
return fmt.Errorf("bridge is not specified")
|
||||
}
|
||||
func (v *veth) detach(n *configs.Network) (err error) {
|
||||
bridge, err := net.InterfaceByName(n.Bridge)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err := netlink.NetworkCreateVethPair(n.HostInterfaceName, n.TempVethPeerName, n.TxQueueLen); err != nil {
|
||||
host, err := net.InterfaceByName(n.HostInterfaceName)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err := netlink.DelFromBridge(host, bridge); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// attach a container network interface to an external network
|
||||
func (v *veth) attach(n *configs.Network) (err error) {
|
||||
bridge, err := net.InterfaceByName(n.Bridge)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
host, err := net.InterfaceByName(n.HostInterfaceName)
|
||||
|
@ -143,6 +153,31 @@ func (v *veth) create(n *network, nspid int) (err error) {
|
|||
if err := netlink.NetworkLinkUp(host); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (v *veth) create(n *network, nspid int) (err error) {
|
||||
tmpName, err := v.generateTempPeerName()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
n.TempVethPeerName = tmpName
|
||||
defer func() {
|
||||
if err != nil {
|
||||
netlink.NetworkLinkDel(n.HostInterfaceName)
|
||||
netlink.NetworkLinkDel(n.TempVethPeerName)
|
||||
}
|
||||
}()
|
||||
if n.Bridge == "" {
|
||||
return fmt.Errorf("bridge is not specified")
|
||||
}
|
||||
if err := netlink.NetworkCreateVethPair(n.HostInterfaceName, n.TempVethPeerName, n.TxQueueLen); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := v.attach(&n.Network); err != nil {
|
||||
return err
|
||||
}
|
||||
child, err := net.InterfaceByName(n.TempVethPeerName)
|
||||
if err != nil {
|
||||
return err
|
||||
|
|
Loading…
Reference in New Issue