func (o *OnDemandProbeServer) getProbe(n *graph.Node, capture *api.Capture) (*probes.FlowProbe, error) { capType := "" if capture.Type != "" { types := common.CaptureTypes[n.Metadata()["Type"].(string)].Allowed for _, t := range types { if t == capture.Type { capType = t break } } if capType == "" { return nil, fmt.Errorf("Capture type %v not allowed on this node: %v", capture, n) } } else { // no capture type defined for this type of node, ex: ovsport c, ok := common.CaptureTypes[n.Metadata()["Type"].(string)] if !ok { return nil, nil } capType = c.Default } probe := o.Probes.GetProbe(capType) if probe == nil { return nil, fmt.Errorf("Unable to find probe for this capture type: %v", capType) } fprobe := probe.(probes.FlowProbe) return &fprobe, nil }
func (o *OnDemandProbeListener) registerProbe(n *graph.Node, capture *api.Capture) bool { o.Lock() defer o.Unlock() if _, ok := o.activeProbes[n.ID]; ok { logging.GetLogger().Debugf("A probe already exists for %s", n.ID) return false } if _, ok := n.Metadata()["Type"]; !ok { logging.GetLogger().Infof("Do not register flow probe, type not supported %v", n) return false } fprobe := o.getProbe(n, capture) if fprobe == nil { logging.GetLogger().Errorf("Failed to register flow probe, unknown type %v", n) return false } ft := o.fta.Alloc(fprobe.AsyncFlowPipeline) if err := fprobe.RegisterProbe(n, capture, ft); err != nil { logging.GetLogger().Debugf("Failed to register flow probe: %s", err.Error()) o.fta.Release(ft) return false } o.activeProbes[n.ID] = ft o.captures[n.ID] = capture logging.GetLogger().Debugf("New active probe on: %v", n) return true }
func (o *OvsSFlowProbesHandler) RegisterProbe(n *graph.Node, capture *api.Capture, ft *flow.Table) error { if isOvsBridge(n) { err := o.RegisterProbeOnBridge(n.Metadata()["UUID"].(string), string(n.ID), ft) if err != nil { return err } } return nil }
func (o *OvsSFlowProbesHandler) UnregisterProbe(n *graph.Node) error { if isOvsBridge(n) { err := o.unregisterProbe(n.Metadata()["UUID"].(string)) if err != nil { return err } } return nil }
func (mapper *OpenContrailMapper) OnNodeDeleted(n *graph.Node) { name, ok := n.Metadata()["Name"] if !ok { return } if n.ID == mapper.vHost.ID { logging.GetLogger().Debugf("Removed %s", name.(string)) mapper.vHost = nil } }
func (o *OnDemandProbeClient) unregisterProbe(node *graph.Node) bool { msg := shttp.NewWSMessage(ondemand.Namespace, "CaptureStop", ondemand.CaptureQuery{NodeID: string(node.ID)}) if !o.wsServer.SendWSMessageTo(msg, node.Host()) { logging.GetLogger().Errorf("Unable to send message to agent: %s", node.Host()) return false } return true }
func (o *OnDemandProbeClient) onNodeEvent(n *graph.Node) { if state, ok := n.Metadata()["State/FlowCapture"]; ok && state.(string) == "ON" { return } for _, capture := range o.captures { if o.matchGremlinExpr(n, capture.GremlinQuery) { go o.registerProbe(n, capture) } } }
func (o *OnDemandProbeServer) OnNodeDeleted(n *graph.Node) { if state, ok := n.Metadata()["State/FlowCapture"]; !ok || state.(string) == "OFF" { return } if o.unregisterProbe(n) { metadata := n.Metadata() metadata["State/FlowCapture"] = "OFF" delete(metadata, "CaptureID") o.Graph.SetMetadata(n, metadata) } }
func (o *OnDemandProbeListener) OnNodeDeleted(n *graph.Node) { if !o.isActive(n) { return } if o.unregisterProbe(n) { metadata := n.Metadata() metadata["State/FlowCapture"] = "OFF" delete(metadata, "CaptureID") o.Graph.SetMetadata(n, metadata) } }
func (mapper *OpenContrailMapper) linkToVhost(node *graph.Node) { name := node.Metadata()["Name"].(string) if mapper.vHost != nil { md := graph.Metadata{"RelationType": "layer2"} if !mapper.graph.AreLinked(node, mapper.vHost, md) { logging.GetLogger().Debugf("Link %s to %s", name, mapper.vHost.Metadata()["Name"].(string)) mapper.graph.Link(node, mapper.vHost, md) } } else { logging.GetLogger().Debugf("Add node %s to pending link list", name) mapper.pendingLinks = append(mapper.pendingLinks, node) } }
func (mapper *NeutronMapper) EnhanceNode(node *graph.Node) { mac, ok := node.Metadata()["MAC"] if !ok { return } portMd, f := mapper.cache.Get(mac.(string)) // If port metadatas have not changed, we return if f && portMd == retrievePortMetadata(node.Metadata()) { return } mapper.nodeUpdaterChan <- node.ID }
func (o *OvsSFlowProbesHandler) RegisterProbe(n *graph.Node, capture *api.Capture, ft *flow.Table) error { tid, ok := n.Metadata()["TID"] if !ok { return fmt.Errorf("No TID for node %v", n) } if isOvsBridge(n) { err := o.RegisterProbeOnBridge(n.Metadata()["UUID"].(string), tid.(string), ft) if err != nil { return err } } return nil }
func getGoPacketFirstLayerType(n *graph.Node) gopacket.LayerType { switch n.Metadata()["Type"].(string) { case "bridge", "bond", "can", "dummy", "hsr", "ifb", "macvlan", "macvtap", "veth", "vlan", "vxlan", "gretap", "ip6gretap", "geneve": return layers.LayerTypeEthernet case "ipoib", "vcan", "ipip", "ipvlan", "lowpan": return layers.LayerTypeIPv4 case "gre": return flow.LayerTypeInGRE case "ip6tnl", "ip6gre", "sit": return layers.LayerTypeIPv6 } return layers.LayerTypeLinuxSLL }
func (u *NetLinkProbe) handleIntfIsChild(intf *graph.Node, link netlink.Link) { // handle pending relationship u.linkPendingChildren(intf, int64(link.Attrs().Index)) // interface being a part of a bridge if link.Attrs().MasterIndex != 0 { u.linkIntfToIndex(intf, int64(link.Attrs().MasterIndex)) } if link.Attrs().ParentIndex != 0 { if _, ok := intf.Metadata()["Vlan"]; ok { u.linkIntfToIndex(intf, int64(int64(link.Attrs().ParentIndex))) } } }
func (mapper *OpenContrailMapper) enhanceNode(node *graph.Node) { // To break update loops if _, ok := node.Metadata()["ExtID/attached-mac"]; ok { return } ifType, ok := node.Metadata()["Type"] if !ok { return } if ifType != "host" && ifType != "netns" { mapper.nodeUpdaterChan <- node.ID } }
func (mapper *NeutronMapper) updateNode(node *graph.Node, attrs *Attributes) { mapper.graph.Lock() tr := mapper.graph.StartMetadataTransaction(node) tr.AddMetadata("Manager", "neutron") if attrs.PortID != "" { tr.AddMetadata("Neutron/PortID", attrs.PortID) } if attrs.TenantID != "" { tr.AddMetadata("Neutron/TenantID", attrs.TenantID) } if attrs.NetworkID != "" { tr.AddMetadata("Neutron/NetworkID", attrs.NetworkID) } if attrs.NetworkName != "" { tr.AddMetadata("Neutron/NetworkName", attrs.NetworkName) } if segID, err := strconv.Atoi(attrs.VNI); err != nil && segID > 0 { tr.AddMetadata("Neutron/VNI", uint64(segID)) } var registerLink *FabricRegisterLinkWSMessage if vm, ok := node.Metadata()["ExtID/vm-uuid"]; ok { if mac, ok := node.Metadata()["ExtID/attached-mac"]; ok { if path := mapper.graph.LookupShortestPath(node, graph.Metadata{"Type": "tun"}, graph.Metadata{"RelationType": "layer2"}); len(path) > 0 { registerLink = &FabricRegisterLinkWSMessage{ ParentNodeID: path[len(path)-1].ID, ParentMetadata: graph.Metadata{"Type": "host", "InstanceID": vm}, ChildMetadata: graph.Metadata{"Type": "device", "MAC": mac}, } } } } tr.Commit() mapper.graph.Unlock() if registerLink != nil { msg := shttp.NewWSMessage(FabricNamespace, "RegisterLink", registerLink) mapper.wsClient.SendWSMessage(msg) } }
func (t *TIDMapper) setTID(parent, child *graph.Node) { if t, ok := child.Metadata()["Type"]; !ok || t == "" { return } if tid, ok := parent.Metadata()["TID"]; ok { tid = tid.(string) + child.Metadata()["Name"].(string) + child.Metadata()["Type"].(string) u, _ := uuid.NewV5(uuid.NamespaceOID, []byte(tid.(string))) t.Graph.AddMetadata(child, "TID", u.String()) } }
func getGoPacketFirstLayerType(n *graph.Node) gopacket.LayerType { if encapType, ok := n.Metadata()["EncapType"]; ok { switch encapType.(string) { case "ether": return layers.LayerTypeEthernet case "gre": return flow.LayerTypeInGRE case "sit", "ipip": return layers.LayerTypeIPv4 case "tunnel6", "gre6": return layers.LayerTypeIPv6 default: logging.GetLogger().Warningf("Encapsulation unknown %s on link %s, defaulting to Ethernet", encapType, n.Metadata()["Name"]) } } else { logging.GetLogger().Warningf("EncapType not found on link %s, defaulting to Ethernet", n.Metadata()["Name"]) } return layers.LayerTypeEthernet }
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) } encapType, ok := n.Metadata()["EncapType"] if !ok || encapType == "" { return fmt.Errorf("No EncapType for node %v", n) } tid, ok := n.Metadata()["TID"] if !ok { return fmt.Errorf("No TID for node %v", n) } id := string(n.ID) ifName := name.(string) if _, ok = p.probes[id]; ok { return fmt.Errorf("Already registered %s", ifName) } port, ok := n.Metadata()["MPLSUDPPort"].(int) if ok { // All gopacket instance of this agent will classify UDP packets coming // from UDP port MPLSUDPPort as MPLS whatever the source interface layers.RegisterUDPPortLayerType(layers.UDPPort(port), layers.LayerTypeMPLS) logging.GetLogger().Infof("MPLSoUDP port: %v", port) } probe := &GoPacketProbe{ NodeTID: tid.(string), state: common.StoppedState, flowTable: ft, } p.probesLock.Lock() p.probes[id] = probe p.probesLock.Unlock() p.wg.Add(1) go func() { defer p.wg.Done() probe.run(p.graph, n, capture) }() return nil }
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 }
// onNodeEvent set TID // TID is UUIDV5(ID/UUID) of "root" node like host, netns, ovsport, fabric // for other nodes TID is UUIDV5(rootTID + Name + Type) func (t *TIDMapper) onNodeEvent(n *graph.Node) { if _, ok := n.Metadata()["TID"]; !ok { if tp, ok := n.Metadata()["Type"]; ok { switch tp.(string) { case "host": t.hostID = n.ID t.Graph.AddMetadata(n, "TID", string(n.ID)) t.setChildrenTID(n) case "netns": tid := string(t.hostID) + n.Metadata()["Path"].(string) + tp.(string) u, _ := uuid.NewV5(uuid.NamespaceOID, []byte(tid)) t.Graph.AddMetadata(n, "TID", u.String()) t.setChildrenTID(n) case "ovsport": tid := string(t.hostID) + n.Metadata()["UUID"].(string) + tp.(string) u, _ := uuid.NewV5(uuid.NamespaceOID, []byte(tid)) t.Graph.AddMetadata(n, "TID", u.String()) t.setChildrenTID(n) default: if n.Metadata()["Probe"] == "fabric" { t.Graph.AddMetadata(n, "TID", string(n.ID)) } else { parents := t.Graph.LookupParents(n, graph.Metadata{}, graph.Metadata{"RelationType": "ownership"}) if len(parents) > 1 { logging.GetLogger().Errorf("A should always only have one ownership parent: %v", n) } else if len(parents) == 1 { t.setTID(parents[0], n) } } } } } }
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 (o *OnDemandProbeListener) getProbe(n *graph.Node, capture *api.Capture) *FlowProbe { capType := "" if capture.Type != "" { types := common.CaptureTypes[n.Metadata()["Type"].(string)].Allowed for _, t := range types { if t == capture.Type { capType = t break } } if capType == "" { return nil } } else { capType = common.CaptureTypes[n.Metadata()["Type"].(string)].Default } probe := o.Probes.GetProbe(capType) if probe == nil { return nil } fprobe := probe.(FlowProbe) return &fprobe }
func (o *OnDemandProbeServer) registerProbe(n *graph.Node, capture *api.Capture) bool { logging.GetLogger().Debugf("Attempting to register probe on node %s", n.Metadata()["Name"].(string)) if o.isActive(n) { logging.GetLogger().Debugf("A probe already exists for %s", n.ID) return false } if _, ok := n.Metadata()["Type"]; !ok { logging.GetLogger().Infof("Unable to register flow probe type of node unknown %v", n) return false } if _, ok := n.Metadata()["TID"]; !ok { logging.GetLogger().Infof("Unable to register flow probe without node TID %v", n) return false } o.Lock() defer o.Unlock() fprobe, err := o.getProbe(n, capture) if fprobe == nil { if err != nil { logging.GetLogger().Error(err.Error()) } return false } ft := o.fta.Alloc(fprobe.AsyncFlowPipeline) ft.SetNodeTID(n.Metadata()["TID"].(string)) if err := fprobe.RegisterProbe(n, capture, ft); err != nil { logging.GetLogger().Debugf("Failed to register flow probe: %s", err.Error()) o.fta.Release(ft) return false } o.activeProbes[n.ID] = ft o.captures[n.ID] = capture logging.GetLogger().Debugf("New active probe on: %v", n) return true }
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 isOvsBridge(n *graph.Node) bool { return n.Metadata()["UUID"] != "" && n.Metadata()["Type"] == "ovsbridge" }
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 *NetLinkProbe) addLinkToTopology(link netlink.Link) { logging.GetLogger().Debugf("Link \"%s(%d)\" added", link.Attrs().Name, link.Attrs().Index) u.Graph.Lock() defer u.Graph.Unlock() driver, _ := u.ethtool.DriverName(link.Attrs().Name) if driver == "" && link.Type() == "bridge" { driver = "bridge" } metadata := graph.Metadata{ "Name": link.Attrs().Name, "Type": link.Type(), "EncapType": link.Attrs().EncapType, "IfIndex": int64(link.Attrs().Index), "MAC": link.Attrs().HardwareAddr.String(), "MTU": int64(link.Attrs().MTU), "Driver": driver, } if link.Type() == "veth" { stats, err := u.ethtool.Stats(link.Attrs().Name) if err != nil { logging.GetLogger().Errorf("Unable get stats from ethtool (%s): %s", link.Attrs().Name, err.Error()) } else if index, ok := stats["peer_ifindex"]; ok { metadata["PeerIfIndex"] = int64(index) } } ipv4 := u.getLinkIPs(link, netlink.FAMILY_V4) if len(ipv4) > 0 { metadata["IPV4"] = ipv4 } ipv6 := u.getLinkIPs(link, netlink.FAMILY_V6) if len(ipv6) > 0 { metadata["IPV6"] = ipv6 } if vlan, ok := link.(*netlink.Vlan); ok { metadata["Vlan"] = vlan.VlanId } if (link.Attrs().Flags & net.FlagUp) > 0 { metadata["State"] = "UP" } else { metadata["State"] = "DOWN" } var intf *graph.Node switch driver { case "bridge": intf = u.addBridgeLinkToTopology(link, metadata) case "openvswitch": intf = u.addOvsLinkToTopology(link, metadata) // always prefer Type from ovs metadata["Type"] = intf.Metadata()["Type"] default: intf = u.addGenericLinkToTopology(link, metadata) } // merge metadata if the interface returned is not a new one if intf != nil { m := intf.Metadata() updated := false for k, nv := range metadata { if ov, ok := m[k]; ok && nv == ov { continue } m[k] = nv updated = true } if updated { u.Graph.SetMetadata(intf, m) } } }