<commit_before>/*
 * Copyright (C) 2015 Red Hat, Inc.
 *
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License.  You may obtain a copy of the License at
 *
 *  http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied.  See the License for the
 * specific language governing permissions and limitations
 * under the License.
 *
 */

package enhancers

import (
	"github.com/pmylund/go-cache"
	"github.com/skydive-project/skydive/flow"
	"github.com/skydive-project/skydive/flow/packet"
	"github.com/skydive-project/skydive/logging"
	"github.com/skydive-project/skydive/topology"
	"github.com/skydive-project/skydive/topology/graph"
)

type GraphFlowEnhancer struct {
	graph.DefaultGraphListener
	Graph    *graph.Graph
	tidCache *tidCache
}

func (gfe *GraphFlowEnhancer) getNodeTID(mac string) string {
	if packet.IsBroadcastMac(mac) || packet.IsMulticastMac(mac) {
		return "*"
	}

	var ce *tidCacheEntry

	if gfe.tidCache != nil {
		var f bool
		if ce, f = gfe.tidCache.get(mac); f {
			return ce.tid
		}
	}

	gfe.Graph.RLock()
	defer gfe.Graph.RUnlock()

	var tid string

	intfs := gfe.Graph.GetNodes(graph.Metadata{"MAC": mac})
	if len(intfs) > 1 {
		logging.GetLogger().Infof("GraphFlowEnhancer found more than one interface for the mac: %s", mac)
	} else if len(intfs) == 1 {
		tid, _ = intfs[0].GetFieldString("TID")
	}

	if gfe.tidCache != nil {
		logging.GetLogger().Debugf("GraphFlowEnhancer set cache %s: %s", mac, tid)
		gfe.tidCache.set(ce, mac, tid)
	}

	return tid
}

func (gfe *GraphFlowEnhancer) Enhance(f *flow.Flow) {
	if f.Link == nil {
		return
	}
	if f.ANodeTID == "" {
		f.ANodeTID = gfe.getNodeTID(f.Link.A)
	}
	if f.BNodeTID == "" {
		f.BNodeTID = gfe.getNodeTID(f.Link.B)
	}
}

func (gfe *GraphFlowEnhancer) OnNodeDeleted(n *graph.Node) {
	if mac, err := n.GetFieldString("MAC"); err == nil {
		logging.GetLogger().Debugf("GraphFlowEnhancer node event del cache %s", mac)
		gfe.tidCache.del(mac)
	}
}

func (gfe *GraphFlowEnhancer) OnEdgeDeleted(e *graph.Edge) {
	// need to reset the entry as edge event of type RelationType means TID update
	if rt, _ := e.GetFieldString("RelationType"); rt == topology.OwnershipLink {
		_, children := gfe.Graph.GetEdgeNodes(e, nil, nil)
		for _, child := range children {
			if mac, err := child.GetFieldString("MAC"); err == nil {
				logging.GetLogger().Debugf("GraphFlowEnhancer edge event del cache %s", mac)
				gfe.tidCache.del(mac)
			}
		}
	}
}

func NewGraphFlowEnhancer(g *graph.Graph, cache *cache.Cache) *GraphFlowEnhancer {
	fe := &GraphFlowEnhancer{
		Graph: g,
	}
	g.AddEventListener(fe)
<commit_msg>flow: enhancer check mac not empty instead of key existing<commit_after>/*
 * Copyright (C) 2015 Red Hat, Inc.
 *
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License.  You may obtain a copy of the License at
 *
 *  http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied.  See the License for the
 * specific language governing permissions and limitations
 * under the License.
 *
 */

package enhancers

import (
	"github.com/pmylund/go-cache"
	"github.com/skydive-project/skydive/flow"
	"github.com/skydive-project/skydive/flow/packet"
	"github.com/skydive-project/skydive/logging"
	"github.com/skydive-project/skydive/topology"
	"github.com/skydive-project/skydive/topology/graph"
)

type GraphFlowEnhancer struct {
	graph.DefaultGraphListener
	Graph    *graph.Graph
	tidCache *tidCache
}

func (gfe *GraphFlowEnhancer) getNodeTID(mac string) string {
	if packet.IsBroadcastMac(mac) || packet.IsMulticastMac(mac) {
		return "*"
	}

	var ce *tidCacheEntry

	if gfe.tidCache != nil {
		var f bool
		if ce, f = gfe.tidCache.get(mac); f {
			return ce.tid
		}
	}

	gfe.Graph.RLock()
	defer gfe.Graph.RUnlock()

	var tid string

	intfs := gfe.Graph.GetNodes(graph.Metadata{"MAC": mac})
	if len(intfs) > 1 {
		logging.GetLogger().Infof("GraphFlowEnhancer found more than one interface for the mac: %s", mac)
	} else if len(intfs) == 1 {
		tid, _ = intfs[0].GetFieldString("TID")
	}

	if gfe.tidCache != nil {
		logging.GetLogger().Debugf("GraphFlowEnhancer set cache %s: %s", mac, tid)
		gfe.tidCache.set(ce, mac, tid)
	}

	return tid
}

func (gfe *GraphFlowEnhancer) Enhance(f *flow.Flow) {
	if f.Link == nil {
		return
	}
	if f.ANodeTID == "" {
		f.ANodeTID = gfe.getNodeTID(f.Link.A)
	}
	if f.BNodeTID == "" {
		f.BNodeTID = gfe.getNodeTID(f.Link.B)
	}
}

func (gfe *GraphFlowEnhancer) OnNodeDeleted(n *graph.Node) {
	if mac, _ := n.GetFieldString("MAC"); mac != "" {
		logging.GetLogger().Debugf("GraphFlowEnhancer node event del cache %s", n.String())
		gfe.tidCache.del(mac)
	}
}

func (gfe *GraphFlowEnhancer) OnEdgeDeleted(e *graph.Edge) {
	// need to reset the entry as edge event of type RelationType means TID update
	if rt, _ := e.GetFieldString("RelationType"); rt == topology.OwnershipLink {
		_, children := gfe.Graph.GetEdgeNodes(e, nil, nil)
		for _, child := range children {
			if mac, _ := child.GetFieldString("MAC"); mac != "" {
				logging.GetLogger().Debugf("GraphFlowEnhancer edge event del cache %s", child.String())
				gfe.tidCache.del(mac)
			}
		}
	}
}

func NewGraphFlowEnhancer(g *graph.Graph, cache *cache.Cache) *GraphFlowEnhancer {
	fe := &GraphFlowEnhancer{
		Graph: g,
	}
	g.AddEventListener(fe)

{'fraction_non_alphanumeric': 0.12382470119521913, 'fraction_numerical': 0.00350597609561753, 'mean_word_length': 3.9730586370839935, 'pattern_counts': {'":': 2, '<': 3, '<?xml version=': 0, '>': 5, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '3479044', 'n_tokens_mistral': 2280, 'n_tokens_neox': 2194, 'n_words': 603}