taleintervenor dfaef9d393 syscontainer-tools: update license to Mulan PSL v2
reason: update license to Mulan PSL v2

Signed-off-by: taleintervenor <taleintervenor@aliyun.com>
2020-04-27 14:54:17 +08:00

248 lines
6.7 KiB
Go

// Copyright (c) Huawei Technologies Co., Ltd. 2018-2019. All rights reserved.
// syscontainer-tools is licensed under the Mulan PSL v2.
// You can use this software according to the terms and conditions of the Mulan PSL v2.
// You may obtain a copy of Mulan PSL v2 at:
// http://license.coscl.org.cn/MulanPSL2
// THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR
// PURPOSE.
// See the Mulan PSL v2 for more details.
// Description: network routes operation
// Author: zhangwei
// Create: 2018-01-18
package libnetwork
import (
"errors"
"fmt"
"net"
"os"
"strings"
"github.com/sirupsen/logrus"
hconfig "isula.org/syscontainer-tools/config"
"isula.org/syscontainer-tools/container"
"isula.org/syscontainer-tools/libnetwork/nsutils"
"isula.org/syscontainer-tools/types"
"github.com/vishvananda/netlink"
)
// AddRoutes will add network routes to contianer and update container config.
func AddRoutes(ctr *container.Container, routes []*types.Route, updateConfigOnly bool) error {
if err := ctr.Lock(); err != nil {
return err
}
defer ctr.Unlock()
// create config file handler.
hConfig, err := hconfig.NewContainerConfig(ctr)
if err != nil {
return err
}
defer hConfig.Flush()
for _, route := range routes {
if err := hConfig.IsConflictRoute(route); err != nil {
return err
}
if err := hConfig.UpdateNetworkRoutes(route, true); err != nil {
return err
}
// Don't insert real route rules when:
// 1. update-config-only flag is set
// 2. or container isn't running(pid=0)
if !updateConfigOnly && ctr.Pid() > 0 && ctr.CheckPidExist() {
if err := AddRouteToContainer(ctr.NetNsPath(), route); err != nil {
// roll back
hConfig.UpdateNetworkRoutes(route, false)
return err
}
}
msg := fmt.Sprintf("Add route to container %s, route: %s done", ctr.Name(), route.String())
fmt.Fprintln(os.Stdout, msg)
logrus.Info(msg)
}
return nil
}
// AddRouteToContainer will add one route to container.
// It will be called by network-hook too.
func AddRouteToContainer(nsPath string, route *types.Route) error {
var err error
src := strings.TrimSpace(route.Src)
dest := strings.TrimSpace(route.Dest)
gw := strings.TrimSpace(route.Gw)
dev := strings.TrimSpace(route.Dev)
if len(src) == 0 && len(gw) == 0 && len(dev) == 0 {
return fmt.Errorf("src or gw or dev name is required")
}
rule := &netlink.Route{}
if dest == "default" {
dest = ""
}
if len(dest) != 0 {
rule.Dst, err = netlink.ParseIPNet(dest)
if err != nil {
return fmt.Errorf("failed to parse dest %q of route rule", dest)
}
}
if len(src) != 0 {
rule.Src = net.ParseIP(src)
if err != nil {
return fmt.Errorf("failed to parse src ip")
}
}
if len(gw) != 0 {
rule.Gw = net.ParseIP(gw)
if err != nil {
return fmt.Errorf("failed to parse gw ip")
}
}
return nsutils.NsInvoke(nsPath,
func(nsFD int) error { return nil },
func(nsFD int) error {
// executed in container
if len(dev) != 0 {
ctrNic, err := netlink.LinkByName(dev)
if err != nil || ctrNic == nil {
return fmt.Errorf("failed to get link by name %s: %v", dev, err)
}
rule.LinkIndex = ctrNic.Attrs().Index
}
if err := netlink.RouteAdd(rule); err != nil {
return fmt.Errorf("failed to add route: %v", err)
}
return nil
})
}
// DelRoutes will remove network routes from contianer and update container config.
func DelRoutes(ctr *container.Container, routes []*types.Route, updateConfigOnly bool) error {
if err := ctr.Lock(); err != nil {
return err
}
defer ctr.Unlock()
// create config file handler.
hConfig, err := hconfig.NewContainerConfig(ctr)
if err != nil {
return err
}
defer hConfig.Flush()
var retErr []error
for _, r := range routes {
if exist := hConfig.IsRouteExist(r); !exist {
errinfo := fmt.Sprint("Route(", r, ") is not added by syscontainer-tools, can not remove it, please check input parameter.")
retErr = append(retErr, errors.New(errinfo))
continue
}
for _, route := range hConfig.GetRoutes(r) {
if err := hConfig.UpdateNetworkRoutes(route, false); err != nil {
retErr = append(retErr, err)
continue
}
// for running container only
if !updateConfigOnly && ctr.Pid() > 0 && ctr.CheckPidExist() {
if err := DelRouteFromContainer(ctr.NetNsPath(), route); err != nil {
// roll back
hConfig.UpdateNetworkRoutes(route, true)
retErr = append(retErr, err)
continue
}
}
fmt.Fprintf(os.Stdout, "Remove route from container %s, route: %s done\n", ctr.Name(), route.String())
logrus.Infof("Remove route from container %s, route: %s done", ctr.Name(), route.String())
}
}
if len(retErr) == 0 {
return nil
}
for i := 0; i < len(retErr); i++ {
retErr[i] = fmt.Errorf("%s", retErr[i].Error())
}
return errors.New(strings.Trim(fmt.Sprint(retErr), "[]"))
}
// DelRouteFromContainer will add one route to container.
func DelRouteFromContainer(nsPath string, route *types.Route) error {
var err error
src := strings.TrimSpace(route.Src)
dest := strings.TrimSpace(route.Dest)
gw := strings.TrimSpace(route.Gw)
dev := strings.TrimSpace(route.Dev)
if len(src) == 0 && len(gw) == 0 && len(dev) == 0 {
return fmt.Errorf("src or gw or dev name is required")
}
rule := &netlink.Route{}
if dest == "default" {
dest = ""
}
if len(dest) != 0 {
rule.Dst, err = netlink.ParseIPNet(dest)
if err != nil {
return fmt.Errorf("failed to parse dest %q of route rule", dest)
}
}
if len(src) != 0 {
rule.Src = net.ParseIP(src)
if err != nil {
return fmt.Errorf("failed to parse src ip")
}
}
if len(gw) != 0 {
rule.Gw = net.ParseIP(gw)
if err != nil {
return fmt.Errorf("failed to parse gw ip")
}
}
return nsutils.NsInvoke(nsPath,
func(nsFD int) error { return nil },
func(nsFD int) error {
// executed in container
if len(dev) != 0 {
ctrNic, err := netlink.LinkByName(dev)
if err != nil || ctrNic == nil {
return fmt.Errorf("failed to get link by name %q: %v", ctrNic, err)
}
rule.LinkIndex = ctrNic.Attrs().Index
}
if err := netlink.RouteDel(rule); err != nil {
if strings.Contains(err.Error(), "no such process") {
return nil
}
return fmt.Errorf("failed to remove route: %v", err)
}
return nil
})
}
// ListRoutes will list all filterd network routes in contianer
func ListRoutes(ctr *container.Container, filter *types.Route) ([]*types.Route, error) {
if err := ctr.Lock(); err != nil {
return nil, err
}
defer ctr.Unlock()
// create config file handler.
hConfig, err := hconfig.NewContainerConfig(ctr)
if err != nil {
return nil, err
}
defer hConfig.Flush()
return hConfig.GetRoutes(filter), nil
}