func (u *NetLinkProbe) handleIntfIsVeth(intf *graph.Node, link netlink.Link) { if link.Type() != "veth" { return } if index, ok := intf.Metadata()["PeerIfIndex"]; ok { peerResolver := func() error { // re get the interface from the graph since the interface could have been deleted if u.Graph.GetNode(intf.ID) == nil { return errors.New("Node not found") } // got more than 1 peer, unable to find the right one, wait for the other to discover peer := u.Graph.LookupFirstNode(graph.Metadata{"IfIndex": index.(int64), "Type": "veth"}) if peer != nil && !u.Graph.AreLinked(peer, intf) { u.Graph.Link(peer, intf, graph.Metadata{"RelationType": "layer2", "Type": "veth"}) return nil } return errors.New("Nodes not linked") } if index.(int64) > intf.Metadata()["IfIndex"].(int64) { if err := peerResolver(); err != nil { retryFnc := func() error { if u.isRunning() == false { return nil } u.Graph.Lock() defer u.Graph.Unlock() return peerResolver() } go common.Retry(retryFnc, 10, 200*time.Millisecond) } } } }
func (p *GoPacketProbesHandler) RegisterProbe(n *graph.Node, capture *api.Capture, ft *flow.Table) error { name, ok := n.Metadata()["Name"] if !ok || name == "" { return fmt.Errorf("No name for node %v", n) } id := string(n.ID) ifName := name.(string) if _, ok := p.probes[id]; ok { return fmt.Errorf("Already registered %s", ifName) } nodes := p.graph.LookupShortestPath(n, graph.Metadata{"Type": "host"}, graph.Metadata{"RelationType": "ownership"}) if len(nodes) == 0 { return fmt.Errorf("Failed to determine probePath for %s", ifName) } runtime.LockOSThread() defer runtime.UnlockOSThread() origns, err := netns.Get() if err != nil { return fmt.Errorf("Error while getting current ns: %s", err.Error()) } defer origns.Close() 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) newns, err := netns.GetFromPath(path) if err != nil { return fmt.Errorf("Error while opening ns %s (path: %s): %s", name, path, err.Error()) } defer newns.Close() if err := netns.Set(newns); err != nil { return fmt.Errorf("Error while switching from root ns to %s (path: %s): %s", name, path, err.Error()) } defer netns.Set(origns) } } probe := &GoPacketProbe{ NodeUUID: id, state: common.StoppedState, flowTable: ft, } switch capture.Type { case "pcap": handle, err := pcap.OpenLive(ifName, snaplen, true, time.Second) if err != nil { return fmt.Errorf("Error while opening device %s: %s", ifName, err.Error()) } if err := handle.SetBPFFilter(capture.BPFFilter); err != nil { return fmt.Errorf("BPF Filter failed: %s", err) } probe.handle = handle probe.packetSource = gopacket.NewPacketSource(handle, getGoPacketFirstLayerType(n)) logging.GetLogger().Infof("PCAP Capture type %s started on %s", capture.Type, n.Metadata()["Name"]) default: var handle *AFPacketHandle fnc := func() error { handle, err = NewAFPacketHandle(ifName, snaplen) if err != nil { return fmt.Errorf("Error while opening device %s: %s", ifName, err.Error()) } return nil } if err = common.Retry(fnc, 2, 100*time.Millisecond); err != nil { return err } probe.handle = handle probe.packetSource = gopacket.NewPacketSource(handle, getGoPacketFirstLayerType(n)) logging.GetLogger().Infof("AfPacket Capture started on %s", n.Metadata()["Name"]) } p.probesLock.Lock() p.probes[id] = probe p.probesLock.Unlock() p.wg.Add(1) go func() { defer p.wg.Done() probe.start() }() return nil }
func (p *GoPacketProbe) run(g *graph.Graph, n *graph.Node, capture *api.Capture) error { atomic.StoreInt64(&p.state, common.RunningState) g.RLock() ifName := n.Metadata()["Name"].(string) firstLayerType := getGoPacketFirstLayerType(n) nscontext, err := topology.NewNetNSContextByNode(g, n) g.RUnlock() defer nscontext.Close() if err != nil { return err } switch capture.Type { case "pcap": handle, err := pcap.OpenLive(ifName, snaplen, true, time.Second) if err != nil { return fmt.Errorf("Error while opening device %s: %s", ifName, err.Error()) } if err := handle.SetBPFFilter(capture.BPFFilter); err != nil { return fmt.Errorf("BPF Filter failed: %s", err) } p.handle = handle p.packetSource = gopacket.NewPacketSource(handle, handle.LinkType()) logging.GetLogger().Infof("PCAP Capture started on %s with First layer: %s", ifName, firstLayerType) default: var handle *AFPacketHandle fnc := func() error { handle, err = NewAFPacketHandle(ifName, snaplen) if err != nil { return fmt.Errorf("Error while opening device %s: %s", ifName, err.Error()) } return nil } if err = common.Retry(fnc, 2, 100*time.Millisecond); err != nil { return err } p.handle = handle p.packetSource = gopacket.NewPacketSource(handle, firstLayerType) logging.GetLogger().Infof("AfPacket Capture started on %s with First layer: %s", ifName, firstLayerType) } // leave the namespace, stay lock in the current thread nscontext.Quit() packetsChan := p.flowTable.Start() defer p.flowTable.Stop() p.feedFlowTable(packetsChan) return nil }
func (u *NetNSProbe) Register(path string, extraMetadata graph.Metadata) *graph.Node { // When a new network namespace has been seen by inotify, the path to // the namespace may still be a regular file, not a bind mount to the // file in /proc/<pid>/tasks/<tid>/ns/net yet, so we wait a bit for the // bind mount to be set up var newns *NetNs err := common.Retry(func() error { var stats syscall.Stat_t fd, err := syscall.Open(path, syscall.O_RDONLY, 0) if err != nil { return err } err = syscall.Fstat(fd, &stats) syscall.Close(fd) if err != nil { return err } if stats.Dev != u.rootNsDev { return fmt.Errorf("%s does not seem to be a valid namespace", path) } newns = &NetNs{path: path, dev: stats.Dev, ino: stats.Ino} return nil }, 10, time.Millisecond*20) if err != nil { logging.GetLogger().Errorf("Could not register namespace: %s", err.Error()) return nil } _, ok := u.pathToNetNS[path] if !ok { u.pathToNetNS[path] = newns } u.Lock() defer u.Unlock() nsString := newns.String() probe, ok := u.nsnlProbes[nsString] if ok { probe.useCount++ logging.GetLogger().Debugf("Increasing counter for namespace %s to %d", nsString, probe.useCount) return probe.Root } u.Graph.Lock() defer u.Graph.Unlock() logging.GetLogger().Debugf("Network Namespace added: %s", nsString) metadata := graph.Metadata{"Name": getNetNSName(path), "Type": "netns", "Path": path} if extraMetadata != nil { for k, v := range extraMetadata { metadata[k] = v } } n := u.Graph.NewNode(graph.GenID(), metadata) u.Graph.Link(u.Root, n, graph.Metadata{"RelationType": "ownership"}) nu := NewNetNsNetLinkTopoUpdater(u.Graph, n) nu.Start(newns) u.nsnlProbes[nsString] = nu return n }