// executeInNetns sets execution of the code following this call to the // network namespace newNs, then moves the thread back to curNs if open, // otherwise to the current netns at the time the function was invoked // In case of success, the caller is expected to execute the returned function // at the end of the code that needs to be executed in the network namespace. // Example: // func jobAt(...) error { // d, err := executeInNetns(...) // if err != nil { return err} // defer d() // < code which needs to be executed in specific netns> // } // TODO: his function probably belongs to netns pkg. func executeInNetns(newNs, curNs netns.NsHandle) (func(), error) { var ( err error moveBack func(netns.NsHandle) error closeNs func() error unlockThd func() ) restore := func() { // order matters if moveBack != nil { moveBack(curNs) } if closeNs != nil { closeNs() } if unlockThd != nil { unlockThd() } } if newNs.IsOpen() { runtime.LockOSThread() unlockThd = runtime.UnlockOSThread if !curNs.IsOpen() { if curNs, err = netns.Get(); err != nil { restore() return nil, fmt.Errorf("could not get current namespace while creating netlink socket: %v", err) } closeNs = curNs.Close } if err := netns.Set(newNs); err != nil { restore() return nil, fmt.Errorf("failed to set into network namespace %d while creating netlink socket: %v", newNs, err) } moveBack = netns.Set } return restore, nil }
// 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) }
func conditionalClose(ns *netns.NsHandle) { if ns != nil && ns.IsOpen() { ns.Close() } }