Example #1
0
func addRoute(cid, CIDR, ifc string, pid int) bool {
	runtime.LockOSThread()
	defer runtime.UnlockOSThread()

	origins, err := netns.Get()
	if err != nil {
		logs.Info("Get orignal namespace failed", err)
		return false
	}
	defer origins.Close()

	ns, err := netns.GetFromPid(pid)
	if err != nil {
		logs.Info("Get container namespace failed", err)
		return false
	}

	netns.Set(ns)
	defer ns.Close()
	defer netns.Set(origins)

	if err := addRouteByLink(CIDR, ifc); err != nil {
		logs.Info("Add route failed", err)
		return false
	}

	logs.Info("Add route success", cid[:12], CIDR, ifc)
	return true
}
Example #2
0
File: utils.go Project: n054/weave
// Search the network namespace of a process for interfaces matching a predicate
// Note that the predicate is called while the goroutine is inside the process' netns
func FindNetDevs(processID int, match func(link netlink.Link) bool) ([]NetDev, error) {
	var netDevs []NetDev

	ns, err := netns.GetFromPid(processID)
	if err != nil {
		if os.IsNotExist(err) {
			return nil, nil
		}
		return nil, err
	}
	defer ns.Close()

	err = weavenet.WithNetNSUnsafe(ns, func() error {
		return forEachLink(func(link netlink.Link) error {
			if match(link) {
				netDev, err := linkToNetDev(link)
				if err != nil {
					return err
				}
				netDevs = append(netDevs, netDev)
			}
			return nil
		})
	})

	return netDevs, err
}
Example #3
0
File: utils.go Project: n054/weave
func GetNetDevsWithPredicate(processID int, predicate func(link netlink.Link) bool) ([]NetDev, error) {
	// Bail out if this container is running in the root namespace
	nsToplevel, err := netns.GetFromPid(1)
	if err != nil {
		return nil, fmt.Errorf("unable to open root namespace: %s", err)
	}
	nsContainr, err := netns.GetFromPid(processID)
	if err != nil {
		return nil, fmt.Errorf("unable to open process %d namespace: %s", processID, err)
	}
	if nsToplevel.Equal(nsContainr) {
		return nil, nil
	}

	return FindNetDevs(processID, predicate)
}
Example #4
0
func setUpVLan(cid, ips string, pid int, veth netlink.Link) bool {
	runtime.LockOSThread()
	defer runtime.UnlockOSThread()

	origns, err := netns.Get()
	if err != nil {
		logs.Info("Get orignal namespace failed", err)
		return false
	}
	defer origns.Close()

	ns, err := netns.GetFromPid(pid)
	if err != nil {
		logs.Info("Get container namespace failed", err)
		return false
	}

	netns.Set(ns)
	defer ns.Close()
	defer netns.Set(origns)

	if err := BindAndSetup(veth, ips); err != nil {
		logs.Info("Bind and setup NIC failed", err)
		DelVlan(veth)
		return false
	}

	logs.Info("Add vlan device success", cid[:12])
	return true
}
Example #5
0
func setDefaultRoute(cid, gateway string, pid int) bool {
	runtime.LockOSThread()
	defer runtime.UnlockOSThread()

	origins, err := netns.Get()
	if err != nil {
		logs.Info("Get orignal namespace failed", err)
		return false
	}
	defer origins.Close()

	ns, err := netns.GetFromPid(pid)
	if err != nil {
		logs.Info("Get container namespace failed", err)
		return false
	}

	netns.Set(ns)
	defer ns.Close()
	defer netns.Set(origins)

	if err := delDefaultRoute(); err != nil {
		logs.Info("Delete default routing table failed", err)
		return false
	}

	if err := addDefaultRoute(gateway); err != nil {
		logs.Info("Add default route failed", err)
		return false
	}

	logs.Info("Set default route success", cid[:12], gateway)
	return true
}
Example #6
0
File: netns.go Project: n054/weave
func WithNetNSLinkByPidUnsafe(pid int, ifName string, work func(link netlink.Link) error) error {
	ns, err := netns.GetFromPid(pid)
	if err != nil {
		return err
	}
	defer ns.Close()

	return WithNetNSLinkUnsafe(ns, ifName, work)
}
Example #7
0
func (probe *DockerProbe) registerContainer(id string) {
	probe.Lock()
	defer probe.Unlock()

	if _, ok := probe.containerMap[id]; ok {
		return
	}
	info, err := probe.client.ContainerInspect(context.Background(), id)
	if err != nil {
		logging.GetLogger().Errorf("Failed to inspect Docker container %s: %s", id, err.Error())
		return
	}

	nsHandle, err := netns.GetFromPid(info.State.Pid)
	if err != nil {
		return
	}
	defer nsHandle.Close()

	namespace := probe.containerNamespace(info.State.Pid)
	logging.GetLogger().Debugf("Register docker container %s and PID %d", info.ID, info.State.Pid)

	var n *graph.Node
	if probe.hostNs.Equal(nsHandle) {
		// The container is in net=host mode
		n = probe.Root
	} else {
		n = probe.Register(namespace, graph.Metadata{"Name": info.Name[1:], "Manager": "docker"})
	}

	probe.Graph.Lock()
	metadata := graph.Metadata{
		"Type":                 "container",
		"Name":                 info.Name[1:],
		"Docker/ContainerID":   info.ID,
		"Docker/ContainerName": info.Name,
		"Docker/ContainerPID":  info.State.Pid,
	}
	containerNode := probe.Graph.NewNode(graph.GenID(), metadata)
	probe.Graph.Link(n, containerNode, graph.Metadata{"RelationType": "membership"})
	probe.Graph.Unlock()

	probe.containerMap[info.ID] = ContainerInfo{
		Pid:  info.State.Pid,
		Node: containerNode,
	}
}
Example #8
0
func EnterDockerNetNs(container *docker.Container) error {
	var err error
	origNs, err = netns.Get()
	if err != nil {
		return log.Criticalf("could not obtain current netns. netns not supported?: %s", err)
	}
	// netns.GetFromDocker() does not work for recent dockers.
	// So we use netns.GetFromPid() directly.
	// https://github.com/vishvananda/netns/pull/10
	newNs, err = netns.GetFromPid(container.State.Pid)
	if err != nil {
		return log.Criticalf("Could not get netns for container %s (pid=%d). The container has exited??: %s", container.ID, container.State.Pid, err)
	}
	runtime.LockOSThread()
	netns.Set(newNs)
	return nil
}
Example #9
0
func parent() {
	cmd := exec.Command("/proc/self/exe", append([]string{"child"}, os.Args[2:]...)...)
	cmd.SysProcAttr = &syscall.SysProcAttr{
		Cloneflags: syscall.CLONE_NEWUTS | syscall.CLONE_NEWPID | syscall.CLONE_NEWNS | syscall.CLONE_NEWNET,
	}
	cmd.Stdin = os.Stdin
	cmd.Stdout = os.Stdout
	cmd.Stderr = os.Stderr

	fmt.Println("Pid:", os.Getpid())

	endpointCreate()

	ns, err := netns.GetFromPid(os.Getpid())
	if err != nil {
		panic(err)
	}

	must(netns.Set(ns))

	temp_path := prepareOverlay("fs/orig", "fs/rootfs")

	if err := cmd.Start(); err != nil {
		fmt.Println("ERROR", err)
		os.Exit(1)
	}

	path := fmt.Sprintf("/proc/%d/ns/net", cmd.Process.Pid)
	tmpfile, err := os.OpenFile(path, os.O_RDONLY, 0)
	if err != nil {
		panic(err)
	}
	nsfd := int(tmpfile.Fd())
	endpointSetNs(nsfd)

	if err := cmd.Wait(); err != nil {
		fmt.Println("ERROR", err)
		os.Exit(1)
	}

	endpointDestroy()

	unmountOverlay("fs/rootfs", temp_path)

}
Example #10
0
File: attach.go Project: n054/weave
func attach(args []string) error {
	if len(args) < 4 {
		cmdUsage("attach-container", "[--no-multicast-route] [--keep-tx-on] <container-id> <bridge-name> <mtu> <cidr>...")
	}

	keepTXOn := false
	withMulticastRoute := true
	for i := 0; i < len(args); {
		switch args[i] {
		case "--no-multicast-route":
			withMulticastRoute = false
			args = append(args[:i], args[i+1:]...)
		case "--keep-tx-on":
			keepTXOn = true
			args = append(args[:i], args[i+1:]...)
		default:
			i++
		}
	}

	pid, nsContainer, err := containerPidAndNs(args[0])
	if err != nil {
		return err
	}
	if nsHost, err := netns.GetFromPid(1); err != nil {
		return fmt.Errorf("unable to open host namespace: %s", err)
	} else if nsHost.Equal(nsContainer) {
		return fmt.Errorf("Container is running in the host network namespace, and therefore cannot be\nconnected to weave. Perhaps the container was started with --net=host.")
	}
	mtu, err := strconv.Atoi(args[2])
	if err != nil && args[3] != "" {
		return fmt.Errorf("unable to parse mtu %q: %s", args[2], err)
	}
	cidrs, err := parseCIDRs(args[3:])
	if err != nil {
		return err
	}

	err = weavenet.AttachContainer(nsContainer, fmt.Sprint(pid), weavenet.VethName, args[1], mtu, withMulticastRoute, cidrs, keepTXOn)
	// If we detected an error but the container has died, tell the user that instead.
	if err != nil && !processExists(pid) {
		err = fmt.Errorf("Container %s died", args[0])
	}
	return err
}
Example #11
0
File: attach.go Project: n054/weave
func containerPidAndNs(containerID string) (int, netns.NsHandle, error) {
	c, err := docker.NewVersionedClientFromEnv("1.18")
	if err != nil {
		return 0, 0, fmt.Errorf("unable to connect to docker: %s", err)
	}
	container, err := c.InspectContainer(containerID)
	if err != nil {
		return 0, 0, fmt.Errorf("unable to inspect container %s: %s", containerID, err)
	}
	if container.State.Pid == 0 {
		return 0, 0, fmt.Errorf("container %s not running", containerID)
	}
	ns, err := netns.GetFromPid(container.State.Pid)
	if err != nil {
		return 0, 0, fmt.Errorf("unable to open namespace for container %s: %s", containerID, err)
	}
	return container.State.Pid, ns, nil
}
Example #12
0
func networkStatsFromNs(pid int) ([]info.InterfaceStats, error) {
	// Lock the OS Thread so we only change the ns for this thread exclusively
	runtime.LockOSThread()
	defer runtime.UnlockOSThread()

	stats := []info.InterfaceStats{}

	// Save the current network namespace
	origns, _ := netns.Get()
	defer origns.Close()

	// Switch to the pid netns
	pidns, err := netns.GetFromPid(pid)
	defer pidns.Close()
	if err != nil {
		return stats, nil
	}
	netns.Set(pidns)

	// Defer setting back to original ns
	defer netns.Set(origns)

	ifaceStats, err := scanInterfaceStats()
	if err != nil {
		return stats, fmt.Errorf("couldn't read network stats: %v", err)
	}

	ifaces, err := net.Interfaces()
	if err != nil {
		return stats, fmt.Errorf("cannot find interfaces: %v", err)
	}

	for _, iface := range ifaces {
		if iface.Flags&net.FlagUp != 0 && iface.Flags&net.FlagLoopback == 0 {
			if s, ok := ifaceStats[iface.Name]; ok {
				stats = append(stats, s)
			}
		}
	}

	return stats, nil
}
func (c Container) ApplyRules(fw firewall) error {

	// Lock the OS Thread so we don't accidentally switch namespaces
	runtime.LockOSThread()
	defer runtime.UnlockOSThread()

	// Save the current network namespace
	origns, _ := netns.Get()
	defer origns.Close()

	// Create a new network namespace
	pid, _ := c.firstPid()

	log.Printf("pid %v", pid)

	newns, _ := netns.GetFromPid(pid)
	defer newns.Close()

	// Switch to the container namespace
	netns.Set(newns)

	// Input
	cmd := append([]string{"-t", "filter", "-F", "INPUT"})
	err := exec.Command(iptablesPath, cmd...).Run()

	if err != nil {
		log.Println("Couldn't apply clear rule")
	}

	for pos, rule := range fw.Input.Rules {

		if rule.Type != "" {
			sport, _ := strconv.Atoi(rule.SourcePort)
			dport, _ := strconv.Atoi(rule.DestinationPort)

			if *Debug {
				log.Printf("ApplyRules - Source : %s SourcePort %v Destination : %s DestinationPort : %v Proto : %s Type : %s", rule.Source, sport, rule.Destination, dport, rule.Proto, rule.Type)
			}
			ippos := pos + 1
			args := []string{"-t", "filter", "-I", "INPUT", strconv.Itoa(ippos), "-p", rule.Proto, "--source", rule.Source, "--destination-port", rule.DestinationPort, "-j", strings.ToUpper(rule.Type), "--wait"}

			if *Debug {
				log.Printf("ApplyRules cmd %s - args : %s", iptablesPath, args)
			}

			cmd := exec.Cmd{Path: iptablesPath, Args: append([]string{iptablesPath}, args...)}
			err := cmd.Run()

			if err != nil {
				log.Println("Couldn't apply rule %v", pos)
			}
		}

	}

	// Switch back to the original namespace
	netns.Set(origns)
	runtime.UnlockOSThread()

	return nil
}
Example #14
0
func AddVlannetwork(etcdval string, vlanid string, containerName string) {
	ss := strings.Split(etcdval, ",")
	hostif := ss[0]
	if ok := utils.ValidateHostIface(hostif); !ok {
		log.Warnf("the host interface not exist")
		return
	}

	vlandevName := hostif + "." + vlanid
	hostEth, _ := netlink.LinkByName(hostif)

	intvlanid, err := strconv.Atoi(vlanid)
	if err != nil {
		log.Warnf("the vlan id convert error: \n")
		return
	}

	var vlandev *netlink.Vlan
	if ok := utils.ValidateHostIface(vlandevName); ok {

	} else {
		//not exist ,create the vlan device
		vlandev = &netlink.Vlan{
			LinkAttrs: netlink.LinkAttrs{
				Name:        vlandevName,
				ParentIndex: hostEth.Attrs().Index,
			},
			VlanId: intvlanid,
		}
		if err := netlink.LinkAdd(vlandev); err != nil {
			log.Warnf("failed to create vlandev: [ %v ] with the error: %s", vlandev, err)
			return
		}
	}

	netlink.LinkSetUp(vlandev)
	macvlanname, _ := utils.GenerateRandomName("vlan"+vlanid, 5)
	//create the macvlan device
	macvlandev := &netlink.Macvlan{
		LinkAttrs: netlink.LinkAttrs{
			Name:        macvlanname,
			ParentIndex: vlandev.Attrs().Index,
		},
		Mode: netlink.MACVLAN_MODE_BRIDGE,
	}

	if err := netlink.LinkAdd(macvlandev); err != nil {
		log.Warnf("failed to create Macvlan: [ %v ] with the error: %s", macvlandev, err)
		return
	}

	dockerPid := utils.DockerPid(containerName)
	//the macvlandev can be use directly, don't get netlink.byname again.
	netlink.LinkSetNsPid(macvlandev, dockerPid)

	runtime.LockOSThread()
	defer runtime.UnlockOSThread()

	//get root network naAddVlannetworkmespace
	origns, _ := netns.Get()
	defer origns.Close()

	//enter the docker container network
	dockerNS, _ := netns.GetFromPid(dockerPid)
	defer dockerNS.Close()

	netns.Set(dockerNS)

	netlink.LinkSetDown(macvlandev)
	netlink.LinkSetName(macvlandev, "eth1")

	_, network, _ := net.ParseCIDR(ss[1])
	if _, ok := ipallocs[vlanid]; !ok {
		log.Fatalf("the ipallocator is null \n")
	}
	ip, _ := ipallocs[vlanid].RequestIP(network, nil)
	ind := strings.LastIndex(ss[1], "/")
	ipstring := ip.String() + ss[1][ind:]

	addr, err := netlink.ParseAddr(ipstring)

	netlink.AddrAdd(macvlandev, addr)
	netlink.LinkSetUp(macvlandev)

	/*
		routes, _ := netlink.RouteList(nil, netlink.FAMILY_V4)
		for _, r := range routes {
			if r.Dst == nil {
				if err := netlink.RouteDel(&r); err != nil {
					log.Warnf("delete the default error: ", err)
				}
			}
		}

		if CligwIP == "" {
			log.Fatal("container gw is null")
		}

		defaultRoute := &netlink.Route{
			Dst:       nil,
			Gw:        net.ParseIP(CligwIP),
			LinkIndex: macvlandev1.Attrs().Index,
		}
		if err := netlink.RouteAdd(defaultRoute); err != nil {
			log.Warnf("create default route error: ", err)
		}
	*/
	netns.Set(origns)
}
Example #15
0
//netlink is not avaible in MAC OS, build fail.
func AddContainerNetworking() {
	if CliIF == "" {
		log.Fatal("the host-interface is missing,please give one")
	}
	if ok := utils.ValidateHostIface(CliIF); !ok {
		log.Fatalf("the host-interface [ %s ] was not found.", CliIF)
	}

	hostmacvlanname, _ := utils.GenerateRandomName(hostprefix, hostlen)
	hostEth, _ := netlink.LinkByName(CliIF)

	//create the macvlan device
	macvlandev := &netlink.Macvlan{
		LinkAttrs: netlink.LinkAttrs{
			Name:        hostmacvlanname,
			ParentIndex: hostEth.Attrs().Index,
		},
		Mode: netlink.MACVLAN_MODE_BRIDGE,
	}
	if err := netlink.LinkAdd(macvlandev); err != nil {
		log.Fatalf("failed to create Macvlan: [ %v ] with the error: %s", macvlandev.Attrs().Name, err)
	}
	//	log.Infof("Created Macvlan port: [ %s ] using the mode: [ %s ]", macvlan.Name, macvlanMode)
	// ugly, actually ,can get the ns from netns.getfromDocker. the netns have many function, netns.getformpid
	// netns.getfromdocker the arg can not be the container name
	dockerPid := utils.DockerPid(CliCName)
	//the macvlandev can be use directly, don't get netlink.byname again.
	netlink.LinkSetNsPid(macvlandev, dockerPid)

	runtime.LockOSThread()
	defer runtime.UnlockOSThread()

	//get root network namespace
	origns, _ := netns.Get()
	defer origns.Close()

	//enter the docker container network
	dockerNS, _ := netns.GetFromPid(dockerPid)
	defer dockerNS.Close()

	netns.Set(dockerNS)

	// use macvlandev can cause error,need type assertion. netlink.Macvlan not must be netlink.Link,fmz(realy? the vlan action add)
	// it is wrong,
	macvlandev1, _ := netlink.LinkByName(macvlandev.Attrs().Name)

	// when the eth is up, set name fail,: Device or resource busy
	netlink.LinkSetDown(macvlandev1)
	netlink.LinkSetName(macvlandev1, "eth1")

	addr, err := netlink.ParseAddr(CliIP)
	if err != nil {
		log.Fatalf("failed to parse the ip address %v", CliIP)
	}
	netlink.AddrAdd(macvlandev1, addr)
	netlink.LinkSetUp(macvlandev1)

	/* set the default route, have some problem. Dst == 0.0.0.0/0? no
	defaultgw := &netlink.Route{
		Dst: nil,
	}
	netlink.RouteDel(defaultgw)
	ip, _ := net.ParseIP("8.8.8.8")
	routes, _ := netlink.RouteGet(ip)
	for _, r := range routes {
		netlink.RouteDel(&r)
	}
	*/

	//if use ip instruction,  it also can config the container, --privileged have no effect.
	// The sublime test code(test this function) is strange, it only can avaiable in first time. And then fail(even need to reboot)
	// got it,

	//following code successfully delete the default route in docker container,but error in my host ,no such process
	routes, _ := netlink.RouteList(nil, netlink.FAMILY_V4)
	for _, r := range routes {
		if r.Dst == nil {
			if err := netlink.RouteDel(&r); err != nil {
				log.Warnf("delete the default error: ", err)
			}
		}
	}

	if CligwIP == "" {
		log.Fatal("container gw is null")
	}

	defaultRoute := &netlink.Route{
		Dst:       nil,
		Gw:        net.ParseIP(CligwIP),
		LinkIndex: macvlandev1.Attrs().Index,
	}
	if err := netlink.RouteAdd(defaultRoute); err != nil {
		log.Warnf("create default route error: ", err)
	}
	netns.Set(origns)
}
Example #16
0
func listNetworks() error {
	// open the database
	dbpath := path.Join(stateDir, ipallocator.DBFile)
	db, err := bolt.Open(dbpath, 0666, nil)
	if err != nil {
		if os.IsNotExist(err) {
			return fmt.Errorf("You have not allocated any IPs")
		}
		return fmt.Errorf("Opening database at %s failed: %v", dbpath, err)
	}
	defer db.Close()

	var networks []network
	if err := db.View(func(tx *bolt.Tx) error {
		// Retrieve the jobs bucket.
		b := tx.Bucket(ipallocator.IPBucket)

		return b.ForEach(func(k, v []byte) error {
			n := network{
				ip: net.ParseIP(string(k)),
			}

			// get the pid
			n.pid, err = strconv.Atoi(string(v))
			if err != nil {
				return fmt.Errorf("parsing pid %s as int failed: %v", v, err)
			}
			// check the process
			_, err := os.FindProcess(n.pid)
			if err != nil {
				n.status = "does not exist"
			} else {
				n.status = "running"
			}

			// get the veth pair from the pid
			n.vethPair, err = vethPair(n.pid, bridgeName)
			if err != nil {
				return fmt.Errorf("Getting vethpair failed for pid %d: %v", n.pid, err)
			}

			// try to get the namespace handle
			n.fd, _ = netns.GetFromPid(n.pid)
			if n.fd <= 0 {
				n.status = "destroyed"
			}

			networks = append(networks, n)
			return nil
		})
	}); err != nil {
		return fmt.Errorf("Getting networks from db failed: %v", err)
	}

	w := tabwriter.NewWriter(os.Stdout, 20, 1, 3, ' ', 0)
	fmt.Fprint(w, "IP\tLOCAL VETH\tPID\tSTATUS\tNS FD\n")
	for _, n := range networks {
		fmt.Fprintf(w, "%s\t%s\t%d\t%s\t%d\n", n.ip.String(), n.vethPair.Attrs().Name, n.pid, n.status, n.fd)
	}
	w.Flush()

	return nil
}
Example #17
0
// configureInterface configures the network interface in the network namespace.
func configureInterface(name string, pid int, addr *net.IPNet, gatewayIP string) error {
	// Lock the OS Thread so we don't accidentally switch namespaces
	runtime.LockOSThread()
	defer runtime.UnlockOSThread()

	// Save the current network namespace
	origns, err := netns.Get()
	if err != nil {
		return fmt.Errorf("Getting current network namespace failed: %v", err)
	}
	defer origns.Close()

	// Get the namespace
	newns, err := netns.GetFromPid(pid)
	if err != nil {
		return fmt.Errorf("Getting network namespace for pid %d failed: %v", pid, err)
	}
	defer newns.Close()

	// Enter the namespace
	if err := netns.Set(newns); err != nil {
		return fmt.Errorf("Entering network namespace failed: %v", err)
	}

	// Find the network interface identified by the name
	iface, err := netlink.LinkByName(name)
	if err != nil {
		return fmt.Errorf("Getting link by name %s failed: %v", name, err)
	}

	// Bring the interface down
	if err := netlink.LinkSetDown(iface); err != nil {
		return fmt.Errorf("Bringing interface [ %#v ] down failed: %v", iface, err)
	}

	// Change the interface name to eth0 in the namespace
	if err := netlink.LinkSetName(iface, containerInterface); err != nil {
		return fmt.Errorf("Renaming interface %s to %s failed: %v", name, defaultContainerInterface, err)
	}

	// Add the IP address
	ipAddr := &netlink.Addr{IPNet: addr, Label: ""}
	if err := netlink.AddrAdd(iface, ipAddr); err != nil {
		return fmt.Errorf("Setting interface %s ip to %s failed: %v", name, addr.String(), err)
	}

	// Bring the interface up
	if err := netlink.LinkSetUp(iface); err != nil {
		return fmt.Errorf("Bringing interface [ %#v ] up failed: %v", iface, err)
	}

	// Add the gateway route
	gw := net.ParseIP(gatewayIP)
	err = netlink.RouteAdd(&netlink.Route{
		Scope:     netlink.SCOPE_UNIVERSE,
		LinkIndex: iface.Attrs().Index,
		Gw:        gw,
	})
	if err != nil {
		return fmt.Errorf("Adding route %s to interface %s failed: %v", gw.String(), name, err)
	}

	// Switch back to the original namespace
	if err := netns.Set(origns); err != nil {
		return fmt.Errorf("Switching back to original namespace failed: %v", err)
	}

	return nil
}
Example #18
0
func AddDHCPNetwork() {

	if ok := utils.ValidateHostIface(flat.CliIF); !ok {
		log.Fatalf("the host-interface [ %s ] was not found.", flat.CliIF)
	}

	hostmacvlanname, _ := utils.GenerateRandomName(hostprefix, hostlen)
	hostEth, _ := netlink.LinkByName(flat.CliIF)

	//create the macvlan device
	macvlandev := &netlink.Macvlan{
		LinkAttrs: netlink.LinkAttrs{
			Name:        hostmacvlanname,
			ParentIndex: hostEth.Attrs().Index,
		},
		Mode: netlink.MACVLAN_MODE_BRIDGE,
	}
	if err := netlink.LinkAdd(macvlandev); err != nil {
		log.Fatalf("failed to create Macvlan: [ %v ] with the error: %s", macvlandev.Attrs().Name, err)
	}

	dockerPid := utils.DockerPid(flat.CliCName)
	netlink.LinkSetNsPid(macvlandev, dockerPid)

	runtime.LockOSThread()
	defer runtime.UnlockOSThread()

	//get root network namespace
	origns, _ := netns.Get()
	defer origns.Close()

	//enter the docker container network
	dockerNS, _ := netns.GetFromPid(dockerPid)
	defer dockerNS.Close()

	//get the dochclient name
	dhcpClientPath := "/home/fmzhen/go/src/github.com/fmzhen/docker-macvlan/macvlan/dhcp/dhcpclient.sh"
	out, err := exec.Command(dhcpClientPath).Output()
	if err != nil {
		log.Fatal("exec the dhcpclient.sh error: ", err)
	}
	dhcpClient := string(out)

	// like ip netns exec xxx, just the netns ,so the command in host can exec
	netns.Set(dockerNS)

	// use macvlandev can cause error,need type assertion. netlink.Macvlan not must be netlink.Link,fmz
	macvlandev1, _ := netlink.LinkByName(macvlandev.Attrs().Name)
	netlink.LinkSetDown(macvlandev1)
	netlink.LinkSetName(macvlandev1, "eth1")
	netlink.LinkSetUp(macvlandev1)

	//delete the default route
	routes, _ := netlink.RouteList(nil, netlink.FAMILY_V4)
	for _, r := range routes {
		if r.Dst == nil {
			if err := netlink.RouteDel(&r); err != nil {
				log.Warnf("delete the default error: ", err)
			}
		}
	}

	//it doesn't work, the problem at the atgs don't pass to the shell script
	dhcpReqpath := "/home/fmzhen/go/src/github.com/fmzhen/docker-macvlan/macvlan/dhcp/dhcpReq.sh"
	exec.Command(dhcpReqpath, dhcpClient, string(dockerPid), flat.CliCName).Run()

	netns.Set(origns)
}
func (c Container) netMetrics() []Metric {
	// Lock the OS Thread so we don't accidentally switch namespaces
	runtime.LockOSThread()
	defer runtime.UnlockOSThread()

	// Save the current network namespace
	origns, _ := netns.Get()
	defer origns.Close()

	// Create a new network namespace
	pid, _ := c.firstPid()

	newns, _ := netns.GetFromPid(pid)
	defer newns.Close()

	// Switch to the container namespace
	netns.Set(newns)

	data, _ := exec.Command("ip", "-s", "-o", "link").Output()

	// Switch back to the original namespace
	netns.Set(origns)
	runtime.UnlockOSThread()

	int_re, _ := regexp.Compile(`^\d+: ([^:]+): .*$`)
	prefix := "network"

	var metrics []Metric
	var interface_name string
	var name string
	var rx []string
	var tx []string

	for _, link_info := range strings.Split(string(data), "\n") {
		split_link_info := strings.Split(link_info, "\\")
		if len(split_link_info) >= 6 {
			interface_name = int_re.FindStringSubmatch(split_link_info[0])[1]
			name = prefix + "." + interface_name
			rx = strings.Fields(split_link_info[3])
			tx = strings.Fields(split_link_info[5])

			if len(rx) == 6 {
				metrics = append(metrics, Metric{name + ".rx.bytes", rx[0]})
				metrics = append(metrics, Metric{name + ".rx.packets", rx[1]})
				metrics = append(metrics, Metric{name + ".rx.errors", rx[2]})
				metrics = append(metrics, Metric{name + ".rx.dropped", rx[3]})
				metrics = append(metrics, Metric{name + ".rx.overrun", rx[4]})
				metrics = append(metrics, Metric{name + ".rx.mcast", rx[5]})
			}

			if len(tx) == 6 {
				metrics = append(metrics, Metric{name + ".tx.bytes", tx[0]})
				metrics = append(metrics, Metric{name + ".tx.packets", tx[1]})
				metrics = append(metrics, Metric{name + ".tx.errors", tx[2]})
				metrics = append(metrics, Metric{name + ".tx.dropped", tx[3]})
				metrics = append(metrics, Metric{name + ".tx.overrun", tx[4]})
				metrics = append(metrics, Metric{name + ".tx.mcast", tx[5]})
			}
		}
	}
	return metrics
}