<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 ovsdb

import (
	"context"
	"fmt"
	"strings"
	"sync"
	"time"

	"github.com/socketplane/libovsdb"

	"github.com/skydive-project/skydive/common"
	"github.com/skydive-project/skydive/config"
	"github.com/skydive-project/skydive/filters"
	"github.com/skydive-project/skydive/logging"
	"github.com/skydive-project/skydive/ovs"
	"github.com/skydive-project/skydive/topology"
	"github.com/skydive-project/skydive/topology/graph"
)

var (
	patchMetadata = graph.Metadata{"RelationType": "layer2", "Type": "patch"}
)

// Probe describes a probe that reads OVS database and updates the graph
type Probe struct {
	sync.Mutex
	Graph        *graph.Graph
	Root         *graph.Node
	OvsMon       *ovsdb.OvsMonitor
	OvsOfProbe   *OvsOfProbe
	uuidToIntf   map[string]*graph.Node
	uuidToPort   map[string]*graph.Node
	intfToPort   map[string]*graph.Node
	portToIntf   map[string]*graph.Node
	portToBridge map[string]*graph.Node
	cancel       context.CancelFunc
}

func isOvsInterfaceType(t string) bool {
	switch t {
	case "dpdk", "dpdkvhostuserclient", "patch", "internal":
		return true
	}

	return false
}

func isOvsDrivenInterface(intf *graph.Node) bool {
	if d, _ := intf.GetFieldString("Driver"); d == "openvswitch" {
		return true
	}

	t, _ := intf.GetFieldString("Type")
	return isOvsInterfaceType(t)
}

// OnConnected event
func (o *Probe) OnConnected(monitor *ovsdb.OvsMonitor) {
}

// OnDisconnected event
func (o *Probe) OnDisconnected(monitor *ovsdb.OvsMonitor) {
}

// OnOvsBridgeUpdate event
func (o *Probe) OnOvsBridgeUpdate(monitor *ovsdb.OvsMonitor, uuid string, row *libovsdb.RowUpdate) {
	o.OnOvsBridgeAdd(monitor, uuid, row)
}

// OnOvsBridgeAdd event
func (o *Probe) OnOvsBridgeAdd(monitor *ovsdb.OvsMonitor, uuid string, row *libovsdb.RowUpdate) {
	o.Lock()
	defer o.Unlock()

	name := row.New.Fields["name"].(string)

	o.Graph.Lock()
	bridge := o.Graph.LookupFirstNode(graph.Metadata{"UUID": uuid})
	if bridge == nil {
		bridge = o.Graph.NewNode(graph.GenID(), graph.Metadata{"Name": name, "UUID": uuid, "Type": "ovsbridge"})
		topology.AddOwnershipLink(o.Graph, o.Root, bridge, nil)
	}

	switch row.New.Fields["ports"].(type) {
	case libovsdb.OvsSet:
		set := row.New.Fields["ports"].(libovsdb.OvsSet)

		for _, i := range set.GoSet {
			u := i.(libovsdb.UUID).GoUUID
			o.portToBridge[u] = bridge

			if port, ok := o.uuidToPort[u]; ok {
				if !topology.HaveOwnershipLink(o.Graph, bridge, port) {
					topology.AddOwnershipLink(o.Graph, bridge, port, nil)
					topology.AddLayer2Link(o.Graph, bridge, port, nil)
				}

				if intf, ok := o.portToIntf[uuid]; ok {
					o.linkIntfTOBridge(bridge, intf)
				}
			}
		}

	case libovsdb.UUID:
		u := row.New.Fields["ports"].(libovsdb.UUID).GoUUID
		o.portToBridge[u] = bridge

		if port, ok := o.uuidToPort[u]; ok {
			if !topology.HaveOwnershipLink(o.Graph, bridge, port) {
				topology.AddOwnershipLink(o.Graph, bridge, port, nil)
				topology.AddLayer2Link(o.Graph, bridge, port, nil)
			}
		}
	}
	o.Graph.Unlock()
	if o.OvsOfProbe != nil {
		o.OvsOfProbe.OnOvsBridgeAdd(bridge)
	}
}

// OnOvsBridgeDel event
func (o *Probe) OnOvsBridgeDel(monitor *ovsdb.OvsMonitor, uuid string, row *libovsdb.RowUpdate) {

	if o.OvsOfProbe != nil {
		o.OvsOfProbe.OnOvsBridgeDel(uuid)
	}
	o.Graph.Lock()
	defer o.Graph.Unlock()
	bridge := o.Graph.LookupFirstNode(graph.Metadata{"UUID": uuid})
	if bridge != nil {
		o.Graph.DelNode(bridge)
	}
}
<commit_msg>ovsdb: fix race in openflow probe<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 ovsdb

import (
	"context"
	"fmt"
	"strings"
	"sync"
	"time"

	"github.com/socketplane/libovsdb"

	"github.com/skydive-project/skydive/common"
	"github.com/skydive-project/skydive/config"
	"github.com/skydive-project/skydive/filters"
	"github.com/skydive-project/skydive/logging"
	"github.com/skydive-project/skydive/ovs"
	"github.com/skydive-project/skydive/topology"
	"github.com/skydive-project/skydive/topology/graph"
)

var (
	patchMetadata = graph.Metadata{"RelationType": "layer2", "Type": "patch"}
)

// Probe describes a probe that reads OVS database and updates the graph
type Probe struct {
	sync.Mutex
	Graph        *graph.Graph
	Root         *graph.Node
	OvsMon       *ovsdb.OvsMonitor
	OvsOfProbe   *OvsOfProbe
	uuidToIntf   map[string]*graph.Node
	uuidToPort   map[string]*graph.Node
	intfToPort   map[string]*graph.Node
	portToIntf   map[string]*graph.Node
	portToBridge map[string]*graph.Node
	cancel       context.CancelFunc
}

func isOvsInterfaceType(t string) bool {
	switch t {
	case "dpdk", "dpdkvhostuserclient", "patch", "internal":
		return true
	}

	return false
}

func isOvsDrivenInterface(intf *graph.Node) bool {
	if d, _ := intf.GetFieldString("Driver"); d == "openvswitch" {
		return true
	}

	t, _ := intf.GetFieldString("Type")
	return isOvsInterfaceType(t)
}

// OnConnected event
func (o *Probe) OnConnected(monitor *ovsdb.OvsMonitor) {
}

// OnDisconnected event
func (o *Probe) OnDisconnected(monitor *ovsdb.OvsMonitor) {
}

// OnOvsBridgeUpdate event
func (o *Probe) OnOvsBridgeUpdate(monitor *ovsdb.OvsMonitor, uuid string, row *libovsdb.RowUpdate) {
	o.OnOvsBridgeAdd(monitor, uuid, row)
}

// OnOvsBridgeAdd event
func (o *Probe) OnOvsBridgeAdd(monitor *ovsdb.OvsMonitor, uuid string, row *libovsdb.RowUpdate) {
	o.Lock()
	defer o.Unlock()

	name := row.New.Fields["name"].(string)

	o.Graph.Lock()
	bridge := o.Graph.LookupFirstNode(graph.Metadata{"UUID": uuid})
	if bridge == nil {
		bridge = o.Graph.NewNode(graph.GenID(), graph.Metadata{"Name": name, "UUID": uuid, "Type": "ovsbridge"})
		topology.AddOwnershipLink(o.Graph, o.Root, bridge, nil)
	}

	switch row.New.Fields["ports"].(type) {
	case libovsdb.OvsSet:
		set := row.New.Fields["ports"].(libovsdb.OvsSet)

		for _, i := range set.GoSet {
			u := i.(libovsdb.UUID).GoUUID
			o.portToBridge[u] = bridge

			if port, ok := o.uuidToPort[u]; ok {
				if !topology.HaveOwnershipLink(o.Graph, bridge, port) {
					topology.AddOwnershipLink(o.Graph, bridge, port, nil)
					topology.AddLayer2Link(o.Graph, bridge, port, nil)
				}

				if intf, ok := o.portToIntf[uuid]; ok {
					o.linkIntfTOBridge(bridge, intf)
				}
			}
		}

	case libovsdb.UUID:
		u := row.New.Fields["ports"].(libovsdb.UUID).GoUUID
		o.portToBridge[u] = bridge

		if port, ok := o.uuidToPort[u]; ok {
			if !topology.HaveOwnershipLink(o.Graph, bridge, port) {
				topology.AddOwnershipLink(o.Graph, bridge, port, nil)
				topology.AddLayer2Link(o.Graph, bridge, port, nil)
			}
		}
	}
	if o.OvsOfProbe != nil {
		o.OvsOfProbe.OnOvsBridgeAdd(bridge)
	}
	o.Graph.Unlock()
}

// OnOvsBridgeDel event
func (o *Probe) OnOvsBridgeDel(monitor *ovsdb.OvsMonitor, uuid string, row *libovsdb.RowUpdate) {

	if o.OvsOfProbe != nil {
		o.OvsOfProbe.OnOvsBridgeDel(uuid)
	}
	o.Graph.Lock()
	defer o.Graph.Unlock()
	bridge := o.Graph.LookupFirstNode(graph.Metadata{"UUID": uuid})
	if bridge != nil {
		o.Graph.DelNode(bridge)
	}
}

{'fraction_non_alphanumeric': 0.12949556282111163, 'fraction_numerical': 0.002568893040635217, 'mean_word_length': 4.056080283353011, 'pattern_counts': {'":': 16, '<': 3, '<?xml version=': 0, '>': 3, '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': '2111622', 'n_tokens_mistral': 3264, 'n_tokens_neox': 3117, 'n_words': 727}