func NewNetNSContextByNode(g *graph.Graph, n *graph.Node) (*common.NetNSContext, error) { name, ok := n.Metadata()["Name"] if !ok || name == "" { return nil, fmt.Errorf("No name for node %v", n) } ifName := name.(string) nodes := g.LookupShortestPath(n, graph.Metadata{"Type": "host"}, graph.Metadata{"RelationType": "ownership"}) if len(nodes) == 0 { return nil, fmt.Errorf("Failed to determine probePath for %s", ifName) } for _, node := range nodes { if node.Metadata()["Type"] == "netns" { name := node.Metadata()["Name"].(string) path := node.Metadata()["Path"].(string) logging.GetLogger().Debugf("Switching to namespace %s (path: %s)", name, path) return common.NewNetNsContext(path) } } return nil, nil }
func (u *NetLinkProbe) start(nsPath string) { var context *common.NetNSContext var err error // Enter the network namespace if necessary if nsPath != "" { context, err = common.NewNetNsContext(nsPath) if err != nil { logging.GetLogger().Errorf("Failed to switch namespace: %s", err.Error()) return } } // Both NewHandle and Subscribe need to done in the network namespace. h, err := netlink.NewHandle(syscall.NETLINK_ROUTE) if err != nil { logging.GetLogger().Errorf("Failed to create netlink handle: %s", err.Error()) context.Close() return } defer h.Delete() s, err := nl.Subscribe(syscall.NETLINK_ROUTE, syscall.RTNLGRP_LINK, syscall.RTNLGRP_IPV4_IFADDR, syscall.RTNLGRP_IPV6_IFADDR) if err != nil { logging.GetLogger().Errorf("Failed to subscribe to netlink messages: %s", err.Error()) context.Close() return } defer s.Close() u.ethtool, err = ethtool.NewEthtool() if err != nil { logging.GetLogger().Errorf("Failed to create ethtool object: %s", err.Error()) context.Close() return } defer u.ethtool.Close() epfd, e := syscall.EpollCreate1(0) if e != nil { logging.GetLogger().Errorf("Failed to create epoll: %s", err.Error()) return } defer syscall.Close(epfd) // Leave the network namespace context.Close() u.wg.Add(1) defer u.wg.Done() atomic.StoreInt64(&u.state, common.RunningState) defer atomic.StoreInt64(&u.state, common.StoppedState) u.netlink = h u.initialize() fd := s.GetFd() err = syscall.SetNonblock(fd, true) if err != nil { logging.GetLogger().Errorf("Failed to set the netlink fd as non-blocking: %s", err.Error()) return } event := syscall.EpollEvent{Events: syscall.EPOLLIN, Fd: int32(fd)} if err = syscall.EpollCtl(epfd, syscall.EPOLL_CTL_ADD, fd, &event); err != nil { logging.GetLogger().Errorf("Failed to control epoll: %s", err.Error()) return } events := make([]syscall.EpollEvent, maxEpollEvents) for atomic.LoadInt64(&u.state) == common.RunningState { n, err := syscall.EpollWait(epfd, events[:], 1000) if err != nil { errno, ok := err.(syscall.Errno) if ok && errno != syscall.EINTR { logging.GetLogger().Errorf("Failed to receive from events from netlink: %s", err.Error()) } continue } if n == 0 { continue } msgs, err := s.Receive() if err != nil { if errno, ok := err.(syscall.Errno); !ok || !errno.Temporary() { logging.GetLogger().Errorf("Failed to receive from netlink messages: %s", err.Error()) return } time.Sleep(1 * time.Second) continue } for _, msg := range msgs { switch msg.Header.Type { case syscall.RTM_NEWLINK: link, err := netlink.LinkDeserialize(msg.Data) if err != nil { logging.GetLogger().Warningf("Failed to deserialize netlink message: %s", err.Error()) continue } u.onLinkAdded(link) case syscall.RTM_DELLINK: link, err := netlink.LinkDeserialize(msg.Data) if err != nil { logging.GetLogger().Warningf("Failed to deserialize netlink message: %s", err.Error()) continue } u.onLinkDeleted(link) case syscall.RTM_NEWADDR: addr, family, ifindex, err := parseAddr(msg.Data) if err != nil { logging.GetLogger().Warningf("Failed to parse newlink message: %s", err.Error()) continue } u.onAddressAdded(addr, family, ifindex) case syscall.RTM_DELADDR: addr, family, ifindex, err := parseAddr(msg.Data) if err != nil { logging.GetLogger().Warningf("Failed to parse newlink message: %s", err.Error()) continue } u.onAddressDeleted(addr, family, ifindex) } } } }