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 }
func nsInvoke(path string, prefunc func(nsFD int) error, postfunc func(callerFD int) error) error { runtime.LockOSThread() defer runtime.UnlockOSThread() origns, err := netns.Get() if err != nil { return err } defer origns.Close() f, err := os.OpenFile(path, os.O_RDONLY, 0) if err != nil { return fmt.Errorf("failed get network namespace %q: %v", path, err) } defer f.Close() nsFD := f.Fd() // Invoked before the namespace switch happens but after the namespace file // handle is obtained. if err := prefunc(int(nsFD)); err != nil { return fmt.Errorf("failed in prefunc: %v", err) } if err = netns.Set(netns.NsHandle(nsFD)); err != nil { return err } defer netns.Set(origns) // Invoked after the namespace switch. return postfunc(int(origns)) }
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 }
func nsInvoke(path string, inNsfunc func(callerFD int) error) error { runtime.LockOSThread() defer runtime.UnlockOSThread() origns, err := netns.Get() if err != nil { return err } defer origns.Close() f, err := os.OpenFile(path, os.O_RDONLY, 0) if err != nil { return fmt.Errorf("failed get network namespace %q: %v", path, err) } defer f.Close() nsFD := f.Fd() if err = netns.Set(netns.NsHandle(nsFD)); err != nil { return err } defer netns.Set(origns) // Invoked after the namespace switch. return inNsfunc(int(origns)) }
func verifySandbox(t *testing.T, s Sandbox, ifaceSuffixes []string) { _, ok := s.(*networkNamespace) if !ok { t.Fatalf("The sandox interface returned is not of type networkNamespace") } origns, err := netns.Get() if err != nil { t.Fatalf("Could not get the current netns: %v", err) } defer origns.Close() f, err := os.OpenFile(s.Key(), os.O_RDONLY, 0) if err != nil { t.Fatalf("Failed top open network namespace path %q: %v", s.Key(), err) } defer f.Close() runtime.LockOSThread() defer runtime.UnlockOSThread() nsFD := f.Fd() if err = netns.Set(netns.NsHandle(nsFD)); err != nil { t.Fatalf("Setting to the namespace pointed to by the sandbox %s failed: %v", s.Key(), err) } defer netns.Set(origns) for _, suffix := range ifaceSuffixes { _, err = netlink.LinkByName(sboxIfaceName + suffix) if err != nil { t.Fatalf("Could not find the interface %s inside the sandbox: %v", sboxIfaceName+suffix, err) } } }
func setupNetNs(nsPath string) (*os.Process, error) { runtime.LockOSThread() defer runtime.UnlockOSThread() origns, err := netns.Get() if err != nil { return nil, err } defer origns.Close() f, err := os.OpenFile(nsPath, os.O_RDONLY, 0) if err != nil { return nil, fmt.Errorf("failed to get network namespace %q: %v", nsPath, err) } defer f.Close() nsFD := f.Fd() if err := netns.Set(netns.NsHandle(nsFD)); err != nil { return nil, fmt.Errorf("failed to set network namespace %q: %v", nsPath, err) } defer netns.Set(origns) cmd := exec.Command("/bin/sh", "-c", "while true; do sleep 1; done") if err := cmd.Start(); err != nil { return nil, fmt.Errorf("failed to start netns process: %v", err) } return cmd.Process, nil }
func checkSandbox(t *testing.T, info libnetwork.EndpointInfo) { origns, err := netns.Get() if err != nil { t.Fatalf("Could not get the current netns: %v", err) } defer origns.Close() key := info.Sandbox().Key() f, err := os.OpenFile(key, os.O_RDONLY, 0) if err != nil { t.Fatalf("Failed to open network namespace path %q: %v", key, err) } defer f.Close() runtime.LockOSThread() defer runtime.UnlockOSThread() nsFD := f.Fd() if err = netns.Set(netns.NsHandle(nsFD)); err != nil { t.Fatalf("Setting to the namespace pointed to by the sandbox %s failed: %v", key, err) } defer netns.Set(origns) _, err = netlink.LinkByName("eth0") if err != nil { t.Fatalf("Could not find the interface eth0 inside the sandbox: %v", err) } _, err = netlink.LinkByName("eth1") if err != nil { t.Fatalf("Could not find the interface eth1 inside the sandbox: %v", err) } }
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 }
func programGateway(path string, gw net.IP) error { runtime.LockOSThread() defer runtime.UnlockOSThread() origns, err := netns.Get() if err != nil { return err } defer origns.Close() f, err := os.OpenFile(path, os.O_RDONLY, 0) if err != nil { return fmt.Errorf("failed get network namespace %q: %v", path, err) } defer f.Close() nsFD := f.Fd() if err = netns.Set(netns.NsHandle(nsFD)); err != nil { return err } defer netns.Set(origns) gwRoutes, err := netlink.RouteGet(gw) if err != nil { return fmt.Errorf("route for the gateway could not be found: %v", err) } return netlink.RouteAdd(&netlink.Route{ Scope: netlink.SCOPE_UNIVERSE, LinkIndex: gwRoutes[0].LinkIndex, Gw: gw, }) }
func (n *networkNamespace) AddInterface(i *Interface) error { n.Lock() i.DstName = fmt.Sprintf("%s%d", i.DstName, n.nextIfIndex) n.nextIfIndex++ n.Unlock() runtime.LockOSThread() defer runtime.UnlockOSThread() origns, err := netns.Get() if err != nil { return err } defer origns.Close() f, err := os.OpenFile(n.path, os.O_RDONLY, 0) if err != nil { return fmt.Errorf("failed get network namespace %q: %v", n.path, err) } defer f.Close() // Find the network interface identified by the SrcName attribute. iface, err := netlink.LinkByName(i.SrcName) if err != nil { return err } // Move the network interface to the destination namespace. nsFD := f.Fd() if err := netlink.LinkSetNsFd(iface, int(nsFD)); err != nil { return err } if err = netns.Set(netns.NsHandle(nsFD)); err != nil { return err } defer netns.Set(origns) // Down the interface before configuring if err := netlink.LinkSetDown(iface); err != nil { return err } // Configure the interface now this is moved in the proper namespace. if err := configureInterface(iface, i); err != nil { return err } // Up the interface. if err := netlink.LinkSetUp(iface); err != nil { return err } n.Lock() n.sinfo.Interfaces = append(n.sinfo.Interfaces, i) n.Unlock() return nil }
func (n *networkNamespace) RemoveInterface(i *Interface) error { runtime.LockOSThread() defer runtime.UnlockOSThread() origns, err := netns.Get() if err != nil { return err } defer origns.Close() f, err := os.OpenFile(n.path, os.O_RDONLY, 0) if err != nil { return fmt.Errorf("failed get network namespace %q: %v", n.path, err) } defer f.Close() nsFD := f.Fd() if err = netns.Set(netns.NsHandle(nsFD)); err != nil { return err } defer netns.Set(origns) // Find the network inteerface identified by the DstName attribute. iface, err := netlink.LinkByName(i.DstName) if err != nil { return err } // Down the interface before configuring if err := netlink.LinkSetDown(iface); err != nil { return err } err = netlink.LinkSetName(iface, i.SrcName) if err != nil { fmt.Println("LinkSetName failed: ", err) return err } // Move the network interface to caller namespace. if err := netlink.LinkSetNsFd(iface, int(origns)); err != nil { fmt.Println("LinkSetNsPid failed: ", err) return err } n.Lock() for index, intf := range n.sinfo.Interfaces { if intf == i { n.sinfo.Interfaces = append(n.sinfo.Interfaces[:index], n.sinfo.Interfaces[index+1:]...) break } } n.Unlock() return nil }
func (tcp *tcpProxySocket) ProxyLoop(service string, proxier *Proxier) { info, found := proxier.getServiceInfo(service) if !found { glog.Errorf("Failed to find service: %s", service) return } for { if !info.isActive() { break } // Block until a connection is made. inConn, err := tcp.Accept() if err != nil { glog.Errorf("Accept failed: %v", err) continue } glog.Infof("Accepted TCP connection from %v to %v", inConn.RemoteAddr(), inConn.LocalAddr()) ns, endpoint, err := proxier.loadBalancer.NextEndpoint(service, inConn.RemoteAddr()) if err != nil { glog.Errorf("Couldn't find an endpoint for %s %v", service, err) inConn.Close() continue } glog.Infof("Mapped service %s to endpoint %s", service, endpoint) // TODO: This could spin up a new goroutine to make the outbound connection, // and keep accepting inbound traffic. if ns.IsOpen() { glog.Infof("Using namespace %v for endpoint %s", ns, endpoint) runtime.LockOSThread() defer runtime.UnlockOSThread() origns, err := netns.Get() if err != nil { glog.Errorf("Failed to get original ns: %v", err) continue } err = netns.Set(ns) if err != nil { glog.Errorf("Failed to set ns: %v", err) continue } defer netns.Set(origns) } outConn, err := retryDial("tcp", endpoint, endpointDialTimeout) if err != nil { // TODO: Try another endpoint? glog.Errorf("Dial failed: %v", err) inConn.Close() continue } // Spin up an async copy loop. proxyTCP(inConn.(*net.TCPConn), outConn.(*net.TCPConn)) } }
func (nu *NetNsNetLinkTopoUpdater) Start(path string) { name := getNetNSName(path) logging.GetLogger().Debugf("Starting NetLinkTopoUpdater for NetNS: %s", name) runtime.LockOSThread() defer runtime.UnlockOSThread() origns, err := netns.Get() if err != nil { logging.GetLogger().Errorf("Error while switching from root ns to %s: %s", name, err.Error()) return } defer origns.Close() time.Sleep(1 * time.Second) newns, err := netns.GetFromPath(path) if err != nil { logging.GetLogger().Errorf("Error while switching from root ns to %s: %s", name, err.Error()) return } defer newns.Close() err = netns.Set(newns) if err != nil { logging.GetLogger().Errorf("Error while switching from root ns to %s: %s", name, err.Error()) return } /* start a netlinks updater inside this namespace */ nu.Lock() nu.nlProbe = NewNetLinkProbe(nu.Graph, nu.Root) nu.Unlock() /* NOTE(safchain) don't Start just Run, need to keep it alive for the time life of the netns * and there is no need to have a new goroutine here */ nu.nlProbe.Run() nu.Lock() nu.nlProbe = nil nu.Unlock() logging.GetLogger().Debugf("NetLinkTopoUpdater stopped for NetNS: %s", name) netns.Set(origns) }
func (s *NetSetup) TearDownTest(c *C) { s.newNS.Close() s.cmd.Process.Kill() netns.Set(s.globalNS) s.globalNS.Close() netlink.LinkDel(s.link) }
func nsInvoke(path string, prefunc func(nsFD int) error, postfunc func(callerFD int) error) error { defer InitOSContext()() f, err := os.OpenFile(path, os.O_RDONLY, 0) if err != nil { return fmt.Errorf("failed get network namespace %q: %v", path, err) } defer f.Close() nsFD := f.Fd() // Invoked before the namespace switch happens but after the namespace file // handle is obtained. if err := prefunc(int(nsFD)); err != nil { return fmt.Errorf("failed in prefunc: %v", err) } if err = netns.Set(netns.NsHandle(nsFD)); err != nil { return err } defer ns.SetNamespace() // Invoked after the namespace switch. return postfunc(ns.ParseHandlerInt()) }
func NewNetNsContext(path string) (*NetNSContext, error) { runtime.LockOSThread() origns, err := netns.Get() if err != nil { return nil, fmt.Errorf("Error while getting current ns: %s", err.Error()) } newns, err := netns.GetFromPath(path) if err != nil { origns.Close() return nil, fmt.Errorf("Error while opening %s: %s", path, err.Error()) } if err = netns.Set(newns); err != nil { newns.Close() origns.Close() return nil, fmt.Errorf("Error while switching from root ns to %s: %s", path, err.Error()) } return &NetNSContext{ origns: origns, newns: newns, }, nil }
func (udp *udpProxySocket) getBackendConn(activeClients *clientCache, cliAddr net.Addr, proxier *Proxier, service string, timeout time.Duration) (net.Conn, error) { activeClients.mu.Lock() defer activeClients.mu.Unlock() svrConn, found := activeClients.clients[cliAddr.String()] if !found { // TODO: This could spin up a new goroutine to make the outbound connection, // and keep accepting inbound traffic. glog.Infof("New UDP connection from %s", cliAddr) ns, endpoint, err := proxier.loadBalancer.NextEndpoint(service, cliAddr) if err != nil { glog.Errorf("Couldn't find an endpoint for %s %v", service, err) return nil, err } glog.Infof("Mapped service %s to endpoint %s", service, endpoint) if ns.IsOpen() { glog.Infof("Using namespace %v for endpoint %s", ns, endpoint) runtime.LockOSThread() netns.Set(ns) defer runtime.UnlockOSThread() } svrConn, err = retryDial("udp", endpoint, endpointDialTimeout) if err != nil { // TODO: Try another endpoint? glog.Errorf("Dial failed: %v", err) return nil, err } activeClients.clients[cliAddr.String()] = svrConn go func(cliAddr net.Addr, svrConn net.Conn, activeClients *clientCache, timeout time.Duration) { defer util.HandleCrash() udp.proxyClient(cliAddr, svrConn, activeClients, timeout) }(cliAddr, svrConn, activeClients, timeout) } return svrConn, nil }
func nsContext() func() { runtime.LockOSThread() return func() { if err := netns.Set(initNs); err != nil { panic(err) } runtime.UnlockOSThread() } }
func WithNetNS(ns netns.NsHandle, work func() error) error { runtime.LockOSThread() defer runtime.UnlockOSThread() oldNs, err := netns.Get() if err == nil { defer oldNs.Close() err = netns.Set(ns) if err == nil { defer netns.Set(oldNs) err = work() } } return nil }
func (n *NetNSContext) Quit() error { if n != nil { if err := netns.Set(n.origns); err != nil { return err } n.newns.Close() n.origns.Close() } return nil }
// InitOSContext initializes OS context while configuring network resources func InitOSContext() func() { runtime.LockOSThread() nsOnce.Do(nsInit) if err := netns.Set(initNs); err != nil { log.Errorf("failed to set to initial namespace, link %s, initns fd %d: %v", getLink(), initNs, err) } return runtime.UnlockOSThread }
func RunInNs(fd netns.NsHandle, fn func() error) error { defer nsContext()() if err := netns.Set(fd); err != nil { return err } if err := fn(); err != nil { return err } return nil }
// SetNamespace sets the initial namespace handler func SetNamespace() error { if err := netns.Set(initNs); err != nil { linkInfo, linkErr := getLink() if linkErr != nil { linkInfo = linkErr.Error() } return fmt.Errorf("failed to set to initial namespace, %v, initns fd %d: %v", linkInfo, initNs, err) } return nil }
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 reexecSetupResolver() { runtime.LockOSThread() defer runtime.UnlockOSThread() if len(os.Args) < 4 { log.Error("invalid number of arguments..") os.Exit(1) } resolverIP, ipPort, _ := net.SplitHostPort(os.Args[2]) _, tcpPort, _ := net.SplitHostPort(os.Args[3]) rules := [][]string{ {"-t", "nat", "-I", outputChain, "-d", resolverIP, "-p", "udp", "--dport", dnsPort, "-j", "DNAT", "--to-destination", os.Args[2]}, {"-t", "nat", "-I", postroutingchain, "-s", resolverIP, "-p", "udp", "--sport", ipPort, "-j", "SNAT", "--to-source", ":" + dnsPort}, {"-t", "nat", "-I", outputChain, "-d", resolverIP, "-p", "tcp", "--dport", dnsPort, "-j", "DNAT", "--to-destination", os.Args[3]}, {"-t", "nat", "-I", postroutingchain, "-s", resolverIP, "-p", "tcp", "--sport", tcpPort, "-j", "SNAT", "--to-source", ":" + dnsPort}, } f, err := os.OpenFile(os.Args[1], os.O_RDONLY, 0) if err != nil { log.Errorf("failed get network namespace %q: %v", os.Args[1], err) os.Exit(2) } defer f.Close() nsFD := f.Fd() if err = netns.Set(netns.NsHandle(nsFD)); err != nil { log.Errorf("setting into container net ns %v failed, %v", os.Args[1], err) os.Exit(3) } // insert outputChain and postroutingchain err = iptables.RawCombinedOutputNative("-t", "nat", "-C", "OUTPUT", "-d", resolverIP, "-j", outputChain) if err == nil { iptables.RawCombinedOutputNative("-t", "nat", "-F", outputChain) } else { iptables.RawCombinedOutputNative("-t", "nat", "-N", outputChain) iptables.RawCombinedOutputNative("-t", "nat", "-I", "OUTPUT", "-d", resolverIP, "-j", outputChain) } err = iptables.RawCombinedOutputNative("-t", "nat", "-C", "POSTROUTING", "-d", resolverIP, "-j", postroutingchain) if err == nil { iptables.RawCombinedOutputNative("-t", "nat", "-F", postroutingchain) } else { iptables.RawCombinedOutputNative("-t", "nat", "-N", postroutingchain) iptables.RawCombinedOutputNative("-t", "nat", "-I", "POSTROUTING", "-d", resolverIP, "-j", postroutingchain) } for _, rule := range rules { if iptables.RawCombinedOutputNative(rule...) != nil { log.Errorf("setting up rule failed, %v", rule) } } }
// GetNetlinkSocketAt opens a netlink socket in the network namespace newNs // and positions the thread back into the network namespace specified by curNs, // when done. If curNs is close, the function derives the current namespace and // moves back into it when done. If newNs is close, the socket will be opened // in the current network namespace. func GetNetlinkSocketAt(newNs, curNs netns.NsHandle, protocol int) (*NetlinkSocket, error) { var err error if newNs.IsOpen() { runtime.LockOSThread() defer runtime.UnlockOSThread() if !curNs.IsOpen() { if curNs, err = netns.Get(); err != nil { return nil, fmt.Errorf("could not get current namespace while creating netlink socket: %v", err) } defer curNs.Close() } if err := netns.Set(newNs); err != nil { return nil, fmt.Errorf("failed to set into network namespace %d while creating netlink socket: %v", newNs, err) } defer netns.Set(curNs) } return getNetlinkSocket(protocol) }
// Redirecter reexec function. func redirecter() { runtime.LockOSThread() defer runtime.UnlockOSThread() if len(os.Args) < 4 { logrus.Error("invalid number of arguments..") os.Exit(1) } var ingressPorts []*PortConfig if os.Args[3] != "" { var err error ingressPorts, err = readPortsFromFile(os.Args[3]) if err != nil { logrus.Errorf("Failed reading ingress ports file: %v", err) os.Exit(2) } } eIP, _, err := net.ParseCIDR(os.Args[2]) if err != nil { logrus.Errorf("Failed to parse endpoint IP %s: %v", os.Args[2], err) os.Exit(3) } rules := [][]string{} for _, iPort := range ingressPorts { rule := strings.Fields(fmt.Sprintf("-t nat -A PREROUTING -d %s -p %s --dport %d -j REDIRECT --to-port %d", eIP.String(), strings.ToLower(PortConfig_Protocol_name[int32(iPort.Protocol)]), iPort.PublishedPort, iPort.TargetPort)) rules = append(rules, rule) } ns, err := netns.GetFromPath(os.Args[1]) if err != nil { logrus.Errorf("failed get network namespace %q: %v", os.Args[1], err) os.Exit(4) } defer ns.Close() if err := netns.Set(ns); err != nil { logrus.Errorf("setting into container net ns %v failed, %v", os.Args[1], err) os.Exit(5) } for _, rule := range rules { if err := iptables.RawCombinedOutputNative(rule...); err != nil { logrus.Errorf("setting up rule failed, %v: %v", rule, err) os.Exit(5) } } }
func (proxier *Proxier) AddService(service, protocol string, port int) (int, error) { glog.Infof("Adding proxy %s on %s:%d", service, proxier.address, port) if proxier.ns.IsOpen() { glog.Infof("Using namespace %v for proxy %s", proxier.ns, service) runtime.LockOSThread() defer runtime.UnlockOSThread() origns, err := netns.Get() if err != nil { return 0, err } err = netns.Set(proxier.ns) if err != nil { return 0, err } defer netns.Set(origns) } sock, err := newProxySocket(protocol, proxier.address, port) if err != nil { return 0, err } _, portStr, err := net.SplitHostPort(sock.Addr().String()) if err != nil { return 0, err } portNum, err := strconv.Atoi(portStr) if err != nil { return 0, err } proxier.setServiceInfo(service, &serviceInfo{ port: portNum, protocol: protocol, active: true, socket: sock, timeout: udpIdleTimeout, }) proxier.startAccepting(service, sock) return portNum, err }
// NewNs creates a new network namespace and returns a handle to it. The caller // is responsible for calling Close on the handle when done with it. func NewNs() netns.NsHandle { runtime.LockOSThread() defer runtime.UnlockOSThread() origns, err := netns.Get() if err != nil { panic(err) } n, err := netns.New() if err != nil { panic(err) } if err := netns.Set(origns); err != nil { panic(err) } return n }
func Exec(fd *os.File, cb func() error) error { runtime.LockOSThread() defer runtime.UnlockOSThread() newns := vishnetns.NsHandle(int(fd.Fd())) origns, _ := vishnetns.Get() defer origns.Close() if err := vishnetns.Set(newns); err != nil { return fmt.Errorf("set netns: %s", err) } err := cb() mustSetNs(origns) // if this happens we definitely can't recover return err }