First Commit of Voltha-Go-Controller from Radisys

Change-Id: I8e2e908e7ab09a4fe3d86849da18b6d69dcf4ab0
diff --git a/internal/pkg/of/flows.go b/internal/pkg/of/flows.go
new file mode 100644
index 0000000..2cc84ac
--- /dev/null
+++ b/internal/pkg/of/flows.go
@@ -0,0 +1,1016 @@
+/*
+* Copyright 2022-present Open Networking Foundation
+* Licensed 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 of
+
+import (
+	"context"
+	"net"
+	"strconv"
+
+	"github.com/google/gopacket/layers"
+
+	"github.com/opencord/voltha-lib-go/v7/pkg/flows"
+	"github.com/opencord/voltha-lib-go/v7/pkg/log"
+	ofp "github.com/opencord/voltha-protos/v5/go/openflow_13"
+	//"github.com/opencord/voltha-protos/v5/go/voltha"
+)
+
+// PbitType type
+type PbitType uint16
+
+// TODO: Port related constants - OF specifies a different value
+// for controller. Need to make sure this is correct
+const (
+	ControllerPort uint32   = 0xfffffffd
+	PbitMatchNone  PbitType = 8
+	PbitMatchAll   PbitType = 0xFF
+)
+
+var logger log.CLogger
+
+var ctx = context.TODO()
+
+// ----------------------------------------------------------
+// Cookie related specifications and utilities
+// ----------------------------------------------------------
+// Though the openflow does not utilize cookies as unique identities of
+// flows, we use cookies as identities in the application. The same
+// may also be used in the VOLTHA if so desired to reduce the complexity
+// of management of flows. In terms of how the cookie is set and is
+// ensured to be unique is:
+// Cookie is a 64 bit value. The first 32 bits are set to the port-id
+// All rules set at the device level are associated with NNI. All other
+// flows, both ingress and egress are associated with the access port.
+// The last 32 bits are used to uniquely identifies flows of a port.
+const (
+	// The flow masks are used to set the MSB of the lower
+	// 32 bits of cookie
+
+	// UsFlowMask constant
+	UsFlowMask uint64 = 0x8000
+	// DsFlowMask constant
+	DsFlowMask uint64 = 0x0000
+
+	// Flow types used to divide the available cookie value range
+	// Each type is allocated 256 flow identities which are plenty
+	// for the known use cases.
+
+	// DhcpArpFlowMask constant
+	DhcpArpFlowMask uint64 = 0x0100
+	// PppoeFlowMask constant
+	PppoeFlowMask uint64 = 0x0100
+	// HsiaFlowMask constant
+	HsiaFlowMask uint64 = 0x0200
+	// DsArpFlowMask constant
+	DsArpFlowMask uint64 = 0x0300
+	// IgmpFlowMask constant
+	IgmpFlowMask uint64 = 0x0400
+	// Dhcpv6FlowMask constant
+	Dhcpv6FlowMask uint64 = 0x0800
+
+	// Flow priorities - Higher the value, higher the priority
+
+	// DhcpFlowPriority constant
+	DhcpFlowPriority uint32 = 5000
+	// ArpFlowPriority constant
+	ArpFlowPriority uint32 = 5000
+	// IgmpFlowPriority constant
+	IgmpFlowPriority uint32 = 5000
+	// McFlowPriority constant
+	McFlowPriority uint32 = 5000
+	// PppoeFlowPriority constant
+	PppoeFlowPriority uint32 = 5000
+	// HsiaFlowPriority constant
+	HsiaFlowPriority uint32 = 100
+)
+
+// CookieSetPort to set port
+func CookieSetPort(cookie uint64, port uint32) uint64 {
+	return cookie | (uint64(port) << 32)
+}
+
+// CookieGetPort to get port
+func CookieGetPort(cookie uint64) uint32 {
+	return uint32(cookie >> 32)
+}
+
+// -------------------------------------------------------
+// The flow match and action related definitions follow
+// -------------------------------------------------------
+// The Ethernet types listed below serve our requirement. We may extend
+// the list as we identify more use cases to be supported.
+
+// EtherType type
+type EtherType uint16
+
+const (
+	// EtherTypeAny constant
+	EtherTypeAny EtherType = 0x0000 // Needs assertion
+	// EtherTypeIpv4 constant
+	EtherTypeIpv4 EtherType = 0x0800
+	// EtherTypeIpv6 constant
+	EtherTypeIpv6 EtherType = 0x86DD
+	// EtherTypePppoeDiscovery constant
+	EtherTypePppoeDiscovery EtherType = 0x8863
+	// EtherTypePppoeSession constant
+	EtherTypePppoeSession EtherType = 0x8864
+	// EtherTypeArp constant
+	EtherTypeArp EtherType = 0x0806
+)
+
+// VLAN related definitions
+// VLANs can take a value between 1 and 4095. VLAN 0 is used to set just
+// the PCP bytes. VLAN 4097 is being used to represent "no VLAN"
+// 4096 is being used to represent "any vlan"
+
+// VlanType type
+type VlanType uint16
+
+const (
+	// VlanAny constant
+	VlanAny VlanType = 0x1000
+	// VlanNone constant
+	VlanNone VlanType = 0x1001
+)
+
+func (vlan *VlanType) String() string {
+	return strconv.Itoa(int(*vlan))
+}
+
+// IP Protocol defintions
+// IP protocol 0xff is reserved and we are using the reserved value to
+// represent that match is not needed.
+
+// IPProtocol type
+type IPProtocol uint8
+
+const (
+	// IPProtocolIgnore constant
+	IPProtocolIgnore IPProtocol = 0xff
+	// IPProtocolTCP constant
+	IPProtocolTCP IPProtocol = 0x06
+	// IPProtocolUDP constant
+	IPProtocolUDP IPProtocol = 0x11
+	// IPProtocolIgmp constant
+	IPProtocolIgmp IPProtocol = 0x02
+	// IPProtocolIcmpv6 constant
+	IPProtocolIcmpv6 IPProtocol = 0x3A
+)
+
+// The following structure is included in each flow which further is
+// used to create a flow. The match structure is used to specify the
+// match rules encoded into the flow.
+
+// Match structure
+type Match struct {
+	InPort        uint32
+	MatchVlan     VlanType
+	SrcMacMatch   bool
+	SrcMacAddr    net.HardwareAddr
+	SrcMacMask    net.HardwareAddr
+	DstMacMatch   bool
+	DstMacAddr    net.HardwareAddr
+	DstMacMask    net.HardwareAddr
+	MatchPbits    bool
+	Pbits         PbitType
+	L3Protocol    EtherType
+	SrcIpv4Match  bool
+	SrcIpv4Addr   net.IP
+	DstIpv4Match  bool
+	DstIpv4Addr   net.IP
+	L4Protocol    IPProtocol
+	SrcPort       uint16
+	DstPort       uint16
+	TableMetadata uint64
+}
+
+// Reset to be used when a Match is created. It sets the values to
+// defaults which results is no match rules at all and thus when
+// applied on a port, match all packets. The match rules must be
+// set before use.
+func (m *Match) Reset() {
+	m.MatchVlan = VlanNone
+	m.SrcMacMatch = false
+	m.DstMacMatch = false
+	m.MatchPbits = false
+	m.L3Protocol = EtherTypeAny
+	m.L4Protocol = IPProtocolIgnore
+	m.SrcPort = 0
+	m.DstPort = 0
+	m.TableMetadata = 0
+}
+
+// SetInPort to set in port
+func (m *Match) SetInPort(port uint32) {
+	m.InPort = port
+}
+
+// SetMatchVlan to set match vlan
+func (m *Match) SetMatchVlan(vlan VlanType) {
+	m.MatchVlan = vlan
+}
+
+// SetPppoeDiscoveryMatch to set L3 protocol
+func (m *Match) SetPppoeDiscoveryMatch() {
+	m.L3Protocol = EtherTypePppoeDiscovery
+}
+
+// SetTableMetadata to set table metadata
+func (m *Match) SetTableMetadata(metadata uint64) {
+	m.TableMetadata = metadata
+}
+
+// SetMatchSrcMac to set source mac address
+func (m *Match) SetMatchSrcMac(mac net.HardwareAddr) {
+	m.SrcMacMatch = true
+	m.SrcMacAddr = mac
+}
+
+// SetMatchDstMac to set destination mac address
+func (m *Match) SetMatchDstMac(mac net.HardwareAddr) {
+	m.DstMacMatch = true
+	m.DstMacAddr = mac
+}
+
+// SetMatchPbit to set pbits
+func (m *Match) SetMatchPbit(pbit PbitType) {
+	m.MatchPbits = true
+	m.Pbits = pbit
+}
+
+// SetMatchSrcIpv4 to set source ipv4 address
+func (m *Match) SetMatchSrcIpv4(ip net.IP) {
+	m.SrcIpv4Match = true
+	m.SrcIpv4Addr = ip
+}
+
+// SetMatchDstIpv4 to set destination ipv4 address
+func (m *Match) SetMatchDstIpv4(ip net.IP) {
+	m.DstIpv4Match = true
+	m.DstIpv4Addr = ip
+}
+
+// SetArpMatch to set L3 protocol as Arp
+func (m *Match) SetArpMatch() {
+	m.L3Protocol = EtherTypeArp
+}
+
+// SetICMPv6Match to set L3 and L4 protocol as IPV6 and ICMPv6
+func (m *Match) SetICMPv6Match() {
+	m.L3Protocol = EtherTypeIpv6
+	m.L4Protocol = IPProtocolIcmpv6
+}
+
+// SetUdpv4Match to set L3 and L4 protocol as IPv4 and UDP
+func (m *Match) SetUdpv4Match() {
+	m.L3Protocol = EtherTypeIpv4
+	m.L4Protocol = IPProtocolUDP
+}
+
+// SetIgmpMatch to set L3 and L4 protocol as IPv4 and Igmp
+func (m *Match) SetIgmpMatch() {
+	m.L3Protocol = EtherTypeIpv4
+	m.L4Protocol = IPProtocolIgmp
+}
+
+// SetUdpv6Match to set L3 and L4 protocol as IPv6 and UDP
+func (m *Match) SetUdpv6Match() {
+	m.L3Protocol = EtherTypeIpv6
+	m.L4Protocol = IPProtocolUDP
+}
+
+// SetIpv4Match to set L3 as IPv4
+func (m *Match) SetIpv4Match() {
+	m.L3Protocol = EtherTypeIpv4
+}
+
+// OutputType type
+type OutputType uint8
+
+const (
+	// OutputTypeDrop constant
+	OutputTypeDrop OutputType = 1
+	// OutputTypeToController constant
+	OutputTypeToController OutputType = 2
+	// OutputTypeToNetwork constant
+	OutputTypeToNetwork OutputType = 3
+	// OutputTypeGoToTable constant
+	OutputTypeGoToTable OutputType = 4
+	// OutputTypeToGroup constant
+	OutputTypeToGroup OutputType = 5
+)
+
+const (
+	// FlowAddSuccess constant
+	FlowAddSuccess = 0
+	// FlowAddFailure constant
+	FlowAddFailure = 1
+	// FlowAddPending constant
+	FlowAddPending = 2
+	// FlowDelPending constant
+	FlowDelPending = 3
+	// FlowDelFailure constant
+	FlowDelFailure = 4
+)
+
+// Action structure
+type Action struct {
+	Output      OutputType
+	PushVlan    []VlanType
+	EtherType   layers.EthernetType
+	SetVlan     VlanType
+	RemoveVlan  int
+	OutPort     uint32
+	GoToTableID uint32
+	Metadata    uint64
+	MeterID     uint32
+	Pcp         PbitType
+}
+
+const (
+	// PbitNone constant
+	PbitNone PbitType = 8
+)
+
+// Reset the action structure
+func (a *Action) Reset() {
+	a.Output = OutputTypeDrop
+	a.PushVlan = make([]VlanType, 0)
+	a.SetVlan = VlanNone
+	a.RemoveVlan = 0
+	a.Metadata = 0
+	a.MeterID = 0
+	a.Pcp = PbitNone
+}
+
+// SetReportToController for set action to report to controller
+func (a *Action) SetReportToController() {
+	a.Output = OutputTypeToController
+	a.OutPort = ControllerPort
+}
+
+// SetPushVlan for set action to push to vlan
+func (a *Action) SetPushVlan(vlan VlanType, etherType layers.EthernetType) {
+	a.PushVlan = append(a.PushVlan, vlan)
+	a.EtherType = etherType
+}
+
+// SetSetVlan to set SetVlan
+func (a *Action) SetSetVlan(vlan VlanType) {
+	a.SetVlan = vlan
+}
+
+// SetPopVlan to set remove vlan counter
+func (a *Action) SetPopVlan() {
+	a.RemoveVlan++
+}
+
+// SetMeterID to set meter id
+func (a *Action) SetMeterID(meterID uint32) {
+	a.MeterID = meterID
+}
+
+// SetWriteMetadata to set metadata
+func (a *Action) SetWriteMetadata(metadata uint64) {
+	a.Metadata = metadata
+}
+
+// SetPcp to set pcp
+func (a *Action) SetPcp(pcp PbitType) {
+	a.Pcp = pcp
+}
+
+// GetWriteMetadata returns metadata
+func (a *Action) GetWriteMetadata() uint64 {
+	return a.Metadata
+}
+
+// SetOutPort to set output port
+func (a *Action) SetOutPort(port uint32) {
+	a.Output = OutputTypeToNetwork
+	a.OutPort = port
+}
+
+// SetOutGroup to set output group
+func (a *Action) SetOutGroup(group uint32) {
+	a.Output = OutputTypeToGroup
+	a.OutPort = group
+}
+
+// SetGoToTable to set GoToTableID
+func (a *Action) SetGoToTable(table uint32) {
+	a.Output = OutputTypeGoToTable
+	a.GoToTableID = table
+}
+
+// VoltSubFlow structure
+type VoltSubFlow struct {
+	Cookie     uint64
+	CookieMask uint64
+	// OldCookie is used in vgc upgrade when there is cookie generation logic change.
+	OldCookie   uint64
+	TableID     uint32
+	Priority    uint32
+	State       uint8
+	ErrorReason string
+	Match
+	Action
+}
+
+// NewVoltSubFlow is constructor for VoltSubFlow
+func NewVoltSubFlow() *VoltSubFlow {
+	var sf VoltSubFlow
+	sf.Match.Reset()
+	sf.Action.Reset()
+	return &sf
+}
+
+// SetTableID to set table id
+func (sf *VoltSubFlow) SetTableID(tableID uint32) {
+	sf.TableID = tableID
+}
+
+// Command type
+type Command uint8
+
+const (
+	// CommandAdd constant
+	CommandAdd Command = 0
+	// CommandDel constant
+	CommandDel Command = 1
+)
+
+// VoltFlow : Definition of a flow
+type VoltFlow struct {
+	Command       Command
+	SubFlows      map[uint64]*VoltSubFlow
+	ForceAction   bool
+	MigrateCookie bool
+	// PortName and PortID to be used for validation of port before flow pushing
+	PortName string
+	PortID   uint32
+}
+
+const (
+	// PrevBwInfo indicates the string returned by core for bandwidth consumed before creating scheduler
+	PrevBwInfo string = "prevBW"
+	// PresentBwInfo indicates the string returned by core for bandwidth consumed after creating scheduler
+	PresentBwInfo string = "presentBW"
+)
+
+// BwAvailDetails consists of bw consumtion details at olt
+type BwAvailDetails struct {
+	PrevBw    string
+	PresentBw string
+}
+
+// -------------------------------------------------------------------
+// OPENFLOW Implementation of flows
+//
+// The flows constructed using the above structures is translated to
+// the VOLTHA OpenFlow GRPC structures. The code below is used to
+// construct the VOLTHA OF GRPC structures.
+const (
+	// DefaultMeterID constant
+	DefaultMeterID uint32 = 0x1
+	// DefaultBufferID constant
+	DefaultBufferID uint32 = 0xffffffff
+	// DefaultOutPort constant
+	DefaultOutPort uint32 = 0xffffffff
+	// DefaultOutGroup constant
+	DefaultOutGroup uint32 = 0xffffffff
+	// DefaultFlags constant
+	DefaultFlags uint32 = 0x1
+)
+
+// NewInportMatch for inport info
+func NewInportMatch(port uint32) *ofp.OfpOxmField {
+	var entry ofp.OfpOxmField
+	var mf ofp.OfpOxmOfbField
+	entry.OxmClass = ofp.OfpOxmClass_OFPXMC_OPENFLOW_BASIC
+	entry.Field = &ofp.OfpOxmField_OfbField{OfbField: &mf}
+	mf.Type = ofp.OxmOfbFieldTypes_OFPXMT_OFB_IN_PORT
+	mf.HasMask = false
+	mf.Value = &ofp.OfpOxmOfbField_Port{Port: port}
+	return &entry
+}
+
+// NewTableMetadataMatch for table metadata
+func NewTableMetadataMatch(metadata uint64) *ofp.OfpOxmField {
+	var entry ofp.OfpOxmField
+	var mf ofp.OfpOxmOfbField
+	entry.OxmClass = ofp.OfpOxmClass_OFPXMC_OPENFLOW_BASIC
+	entry.Field = &ofp.OfpOxmField_OfbField{OfbField: &mf}
+	mf.Type = ofp.OxmOfbFieldTypes_OFPXMT_OFB_METADATA
+	mf.HasMask = false
+	mf.Value = &ofp.OfpOxmOfbField_TableMetadata{TableMetadata: metadata}
+	return &entry
+}
+
+// NewSrcMacAddrMatch for source mac address info
+func NewSrcMacAddrMatch(addr []byte) *ofp.OfpOxmField {
+	var entry ofp.OfpOxmField
+	var mf ofp.OfpOxmOfbField
+	entry.OxmClass = ofp.OfpOxmClass_OFPXMC_OPENFLOW_BASIC
+	entry.Field = &ofp.OfpOxmField_OfbField{OfbField: &mf}
+	mf.Type = ofp.OxmOfbFieldTypes_OFPXMT_OFB_ETH_SRC
+	mf.HasMask = false
+	mf.Value = &ofp.OfpOxmOfbField_EthSrc{EthSrc: addr}
+	return &entry
+}
+
+// NewDstMacAddrMatch for destination mac address info
+func NewDstMacAddrMatch(addr []byte) *ofp.OfpOxmField {
+	var entry ofp.OfpOxmField
+	var mf ofp.OfpOxmOfbField
+	entry.OxmClass = ofp.OfpOxmClass_OFPXMC_OPENFLOW_BASIC
+	entry.Field = &ofp.OfpOxmField_OfbField{OfbField: &mf}
+	mf.Type = ofp.OxmOfbFieldTypes_OFPXMT_OFB_ETH_DST
+	mf.HasMask = false
+	mf.Value = &ofp.OfpOxmOfbField_EthDst{EthDst: addr}
+	return &entry
+}
+
+// NewVlanMatch for vlan info
+func NewVlanMatch(vlan uint16) *ofp.OfpOxmField {
+	var entry ofp.OfpOxmField
+	var mf ofp.OfpOxmOfbField
+	entry.OxmClass = ofp.OfpOxmClass_OFPXMC_OPENFLOW_BASIC
+	entry.Field = &ofp.OfpOxmField_OfbField{OfbField: &mf}
+	mf.Type = ofp.OxmOfbFieldTypes_OFPXMT_OFB_VLAN_VID
+	mf.HasMask = false
+	mf.Value = &ofp.OfpOxmOfbField_VlanVid{VlanVid: uint32(vlan&0x0fff + 0x1000)}
+	mf.Mask = &ofp.OfpOxmOfbField_VlanVidMask{VlanVidMask: uint32(0x1000)}
+	return &entry
+}
+
+// NewPcpMatch for pcp info
+func NewPcpMatch(pbits PbitType) *ofp.OfpOxmField {
+	var entry ofp.OfpOxmField
+	var mf ofp.OfpOxmOfbField
+	entry.OxmClass = ofp.OfpOxmClass_OFPXMC_OPENFLOW_BASIC
+	entry.Field = &ofp.OfpOxmField_OfbField{OfbField: &mf}
+	mf.Type = ofp.OxmOfbFieldTypes_OFPXMT_OFB_VLAN_PCP
+	mf.HasMask = false
+	mf.Value = &ofp.OfpOxmOfbField_VlanPcp{VlanPcp: uint32(pbits)}
+	return &entry
+}
+
+// NewEthTypeMatch for eth type info
+func NewEthTypeMatch(l3proto uint16) *ofp.OfpOxmField {
+	var entry ofp.OfpOxmField
+	var mf ofp.OfpOxmOfbField
+	entry.OxmClass = ofp.OfpOxmClass_OFPXMC_OPENFLOW_BASIC
+	entry.Field = &ofp.OfpOxmField_OfbField{OfbField: &mf}
+	mf.Type = ofp.OxmOfbFieldTypes_OFPXMT_OFB_ETH_TYPE
+	mf.HasMask = false
+	mf.Value = &ofp.OfpOxmOfbField_EthType{EthType: uint32(l3proto)}
+	return &entry
+}
+
+// ipv4ToUint to convert ipv4 to uint
+func ipv4ToUint(ip net.IP) uint32 {
+	result := uint32(0)
+	addr := ip.To4()
+	if addr == nil {
+		logger.Warnw(ctx, "Invalid Group Addr", log.Fields{"IP": ip})
+		return 0
+	}
+	result = result + uint32(addr[0])<<24
+	result = result + uint32(addr[1])<<16
+	result = result + uint32(addr[2])<<8
+	result = result + uint32(addr[3])
+	return result
+}
+
+// NewIpv4SrcMatch for ipv4 source address
+func NewIpv4SrcMatch(ip net.IP) *ofp.OfpOxmField {
+	var entry ofp.OfpOxmField
+	var mf ofp.OfpOxmOfbField
+	entry.OxmClass = ofp.OfpOxmClass_OFPXMC_OPENFLOW_BASIC
+	entry.Field = &ofp.OfpOxmField_OfbField{OfbField: &mf}
+	mf.Type = ofp.OxmOfbFieldTypes_OFPXMT_OFB_IPV4_SRC
+	mf.HasMask = false
+	mf.Value = &ofp.OfpOxmOfbField_Ipv4Src{Ipv4Src: ipv4ToUint(ip)}
+	return &entry
+}
+
+// NewIpv4DstMatch for ipv4 destination address
+func NewIpv4DstMatch(ip net.IP) *ofp.OfpOxmField {
+	var entry ofp.OfpOxmField
+	var mf ofp.OfpOxmOfbField
+	entry.OxmClass = ofp.OfpOxmClass_OFPXMC_OPENFLOW_BASIC
+	entry.Field = &ofp.OfpOxmField_OfbField{OfbField: &mf}
+	mf.Type = ofp.OxmOfbFieldTypes_OFPXMT_OFB_IPV4_DST
+	mf.HasMask = false
+	mf.Value = &ofp.OfpOxmOfbField_Ipv4Dst{Ipv4Dst: ipv4ToUint(ip)}
+	return &entry
+}
+
+// NewIPProtoMatch for ip proto info
+func NewIPProtoMatch(l4proto uint16) *ofp.OfpOxmField {
+	var entry ofp.OfpOxmField
+	var mf ofp.OfpOxmOfbField
+	entry.OxmClass = ofp.OfpOxmClass_OFPXMC_OPENFLOW_BASIC
+	entry.Field = &ofp.OfpOxmField_OfbField{OfbField: &mf}
+	mf.Type = ofp.OxmOfbFieldTypes_OFPXMT_OFB_IP_PROTO
+	mf.HasMask = false
+	mf.Value = &ofp.OfpOxmOfbField_IpProto{IpProto: uint32(l4proto)}
+	return &entry
+}
+
+// NewUDPSrcMatch for source udp info
+func NewUDPSrcMatch(port uint16) *ofp.OfpOxmField {
+	var entry ofp.OfpOxmField
+	var mf ofp.OfpOxmOfbField
+	entry.OxmClass = ofp.OfpOxmClass_OFPXMC_OPENFLOW_BASIC
+	entry.Field = &ofp.OfpOxmField_OfbField{OfbField: &mf}
+	mf.Type = ofp.OxmOfbFieldTypes_OFPXMT_OFB_UDP_SRC
+	mf.HasMask = false
+	mf.Value = &ofp.OfpOxmOfbField_UdpSrc{UdpSrc: uint32(port)}
+	return &entry
+}
+
+// NewUDPDstMatch for destination udp info
+func NewUDPDstMatch(port uint16) *ofp.OfpOxmField {
+	var entry ofp.OfpOxmField
+	var mf ofp.OfpOxmOfbField
+	entry.OxmClass = ofp.OfpOxmClass_OFPXMC_OPENFLOW_BASIC
+	entry.Field = &ofp.OfpOxmField_OfbField{OfbField: &mf}
+	mf.Type = ofp.OxmOfbFieldTypes_OFPXMT_OFB_UDP_DST
+	mf.HasMask = false
+	mf.Value = &ofp.OfpOxmOfbField_UdpDst{UdpDst: uint32(port)}
+	return &entry
+}
+
+// NewMeterIDInstruction for meter id instructions
+func NewMeterIDInstruction(meterID uint32) *ofp.OfpInstruction {
+	var meter ofp.OfpInstruction
+	meter.Type = uint32(ofp.OfpInstructionType_OFPIT_METER)
+	meter.Data = &ofp.OfpInstruction_Meter{
+		Meter: &ofp.OfpInstructionMeter{
+			MeterId: meterID,
+		},
+	}
+	return &meter
+}
+
+// NewGoToTableInstruction for go to table instructions
+func NewGoToTableInstruction(table uint32) *ofp.OfpInstruction {
+	var gotoTable ofp.OfpInstruction
+	gotoTable.Type = uint32(ofp.OfpInstructionType_OFPIT_GOTO_TABLE)
+	gotoTable.Data = &ofp.OfpInstruction_GotoTable{
+		GotoTable: &ofp.OfpInstructionGotoTable{
+			TableId: table,
+		},
+	}
+	return &gotoTable
+}
+
+// NewPopVlanInstruction for pop vlan instructions
+func NewPopVlanInstruction() *ofp.OfpInstruction {
+	var removeTag ofp.OfpInstruction
+	var actions ofp.OfpInstructionActions
+	removeTag.Type = uint32(ofp.OfpInstructionType_OFPIT_APPLY_ACTIONS)
+	removeTag.Data = &ofp.OfpInstruction_Actions{
+		Actions: &actions,
+	}
+	action := flows.PopVlan()
+	actions.Actions = append(actions.Actions, action)
+	return &removeTag
+}
+
+// NewWriteMetadataInstruction for write metadata instructions
+func NewWriteMetadataInstruction(metadata uint64) *ofp.OfpInstruction {
+	var md ofp.OfpInstruction
+	md.Type = uint32(ofp.OfpInstructionType_OFPIT_WRITE_METADATA)
+	md.Data = &ofp.OfpInstruction_WriteMetadata{WriteMetadata: &ofp.OfpInstructionWriteMetadata{Metadata: metadata}}
+	return &md
+}
+
+// NewPopVlanAction for pop vlan action
+func NewPopVlanAction() *ofp.OfpAction {
+	return flows.PopVlan()
+}
+
+// NewPushVlanInstruction for push vlan instructions
+func NewPushVlanInstruction(vlan uint16, etherType uint32) *ofp.OfpInstruction {
+	var addTag ofp.OfpInstruction
+	var actions ofp.OfpInstructionActions
+	addTag.Type = uint32(ofp.OfpInstructionType_OFPIT_APPLY_ACTIONS)
+	addTag.Data = &ofp.OfpInstruction_Actions{
+		Actions: &actions,
+	}
+	pushAction := flows.PushVlan(etherType)
+	actions.Actions = append(actions.Actions, pushAction)
+	var setField ofp.OfpOxmOfbField
+	setField.Type = ofp.OxmOfbFieldTypes_OFPXMT_OFB_VLAN_VID
+	setField.HasMask = false
+	setField.Value = &ofp.OfpOxmOfbField_VlanVid{
+		VlanVid: uint32(vlan&0x0fff + 0x1000),
+	}
+	setAction := flows.SetField(&setField)
+	actions.Actions = append(actions.Actions, setAction)
+	return &addTag
+}
+
+// NewPushVlanAction for push vlan action
+func NewPushVlanAction(etherType uint32) *ofp.OfpAction {
+	pushAction := flows.PushVlan(etherType)
+	return pushAction
+}
+
+// NewSetVlanAction for set vlan action
+func NewSetVlanAction(vlan uint16) *ofp.OfpAction {
+	var setField ofp.OfpOxmOfbField
+	setField.Type = ofp.OxmOfbFieldTypes_OFPXMT_OFB_VLAN_VID
+	setField.HasMask = false
+	and := (vlan & 0xfff)
+	or := and + 0x1000
+	v := uint32(vlan&0x0fff + 0x1000)
+	logger.Infow(ctx, "Vlan Construction", log.Fields{"Vlan": vlan, "vlan&0x0fff": and, "OR": or, "final": v})
+	setField.Value = &ofp.OfpOxmOfbField_VlanVid{
+		VlanVid: uint32(vlan&0x0fff + 0x1000),
+	}
+	setAction := flows.SetField(&setField)
+	return setAction
+}
+
+// NewSetPcpAction for set pcap action
+func NewSetPcpAction(pbits PbitType) *ofp.OfpAction {
+	var setField ofp.OfpOxmOfbField
+	setField.Type = ofp.OxmOfbFieldTypes_OFPXMT_OFB_VLAN_PCP
+	setField.HasMask = false
+	setField.Value = &ofp.OfpOxmOfbField_VlanPcp{VlanPcp: uint32(pbits)}
+	setAction := flows.SetField(&setField)
+	return setAction
+}
+
+// NewOutputInstruction for output instructions
+func NewOutputInstruction(port uint32) *ofp.OfpInstruction {
+	var outport ofp.OfpInstruction
+	var actions ofp.OfpInstructionActions
+	outport.Type = uint32(ofp.OfpInstructionType_OFPIT_APPLY_ACTIONS)
+	outport.Data = &ofp.OfpInstruction_Actions{
+		Actions: &actions,
+	}
+	action := flows.Output(port, 65535)
+	actions.Actions = append(actions.Actions, action)
+	return &outport
+}
+
+// NewOutputAction for output action
+func NewOutputAction(port uint32) *ofp.OfpAction {
+	return flows.Output(port, 65535)
+}
+
+// NewGroupOutputInstruction for group output instructions
+func NewGroupOutputInstruction(group uint32) *ofp.OfpInstruction {
+	var outgroup ofp.OfpInstruction
+	var actions ofp.OfpInstructionActions
+	outgroup.Type = uint32(ofp.OfpInstructionType_OFPIT_APPLY_ACTIONS)
+	outgroup.Data = &ofp.OfpInstruction_Actions{
+		Actions: &actions,
+	}
+	action := flows.Group(group)
+	actions.Actions = append(actions.Actions, action)
+	return &outgroup
+}
+
+// NewGroupAction for group action
+func NewGroupAction(group uint32) *ofp.OfpAction {
+	return flows.Group(group)
+}
+
+// CreateMatchAndActions to create match list and action
+func CreateMatchAndActions(f *VoltSubFlow) ([]*ofp.OfpOxmField, []*ofp.OfpInstruction) {
+	logger.Debug(ctx, "Create Match and Action called")
+
+	// Return values declared here
+	var matchList []*ofp.OfpOxmField
+	var instructions []*ofp.OfpInstruction
+
+	// Construct the match rules
+	// Add match in port
+	if f.Match.InPort != 0 {
+		entry := NewInportMatch(uint32(f.Match.InPort))
+		matchList = append(matchList, entry)
+	}
+
+	// Add table metadata match
+	if f.Match.TableMetadata != 0 {
+		entry := NewTableMetadataMatch(uint64(f.Match.TableMetadata))
+		matchList = append(matchList, entry)
+	}
+
+	// Add Src MAC address match
+	if f.SrcMacMatch {
+		entry := NewSrcMacAddrMatch(f.SrcMacAddr)
+		matchList = append(matchList, entry)
+	}
+
+	// Add Src MAC address match
+	if f.DstMacMatch {
+		entry := NewDstMacAddrMatch(f.DstMacAddr)
+		matchList = append(matchList, entry)
+	}
+
+	// Add VLAN tag match
+	if f.MatchVlan != VlanNone {
+		entry := NewVlanMatch(uint16(f.MatchVlan))
+		matchList = append(matchList, entry)
+	}
+
+	if f.MatchPbits {
+		entry := NewPcpMatch(f.Pbits)
+		matchList = append(matchList, entry)
+	}
+
+	// Add EtherType match
+	if f.L3Protocol != EtherTypeAny {
+		entry := NewEthTypeMatch(uint16(f.L3Protocol))
+		matchList = append(matchList, entry)
+	}
+
+	// Add the Src IPv4 addr match
+	if f.SrcIpv4Match {
+		entry := NewIpv4SrcMatch(f.SrcIpv4Addr)
+		matchList = append(matchList, entry)
+	}
+
+	// Add the Dst IPv4 addr match
+	if f.DstIpv4Match {
+		entry := NewIpv4DstMatch(f.DstIpv4Addr)
+		matchList = append(matchList, entry)
+	}
+
+	// Add IP protocol match
+	if f.L4Protocol != IPProtocolIgnore {
+		entry := NewIPProtoMatch(uint16(f.L4Protocol))
+		matchList = append(matchList, entry)
+	}
+
+	// Add UDP Source port match
+	if f.SrcPort != 0 {
+		entry := NewUDPSrcMatch(uint16(f.SrcPort))
+		matchList = append(matchList, entry)
+	}
+
+	// Add UDP Dest port match
+	if f.DstPort != 0 {
+		entry := NewUDPDstMatch(uint16(f.DstPort))
+		matchList = append(matchList, entry)
+	}
+
+	// Construct the instructions
+	// Add a GOTO table action
+	if f.Output == OutputTypeGoToTable {
+		instruction := NewGoToTableInstruction(f.GoToTableID)
+		instructions = append(instructions, instruction)
+	}
+
+	// Add the meter instruction
+	if f.MeterID != 0 {
+		instruction := NewMeterIDInstruction(f.MeterID)
+		instructions = append(instructions, instruction)
+	}
+
+	// Add the metadata instruction
+	if f.Metadata != 0 {
+		instruction := NewWriteMetadataInstruction(f.Metadata)
+		instructions = append(instructions, instruction)
+	}
+
+	// The below are all apply actions. All of these could be combined into
+	// a single instruction.
+	{
+		var instruction ofp.OfpInstruction
+		var actions ofp.OfpInstructionActions
+		instruction.Type = uint32(ofp.OfpInstructionType_OFPIT_APPLY_ACTIONS)
+		instruction.Data = &ofp.OfpInstruction_Actions{
+			Actions: &actions,
+		}
+
+		// Apply action of popping the VLAN
+		if f.RemoveVlan != 0 {
+			for i := 0; i < f.RemoveVlan; i++ {
+				action := NewPopVlanAction()
+				actions.Actions = append(actions.Actions, action)
+			}
+		}
+
+		if f.SetVlan != VlanNone {
+			action := NewSetVlanAction(uint16(f.SetVlan))
+			actions.Actions = append(actions.Actions, action)
+		}
+
+		if f.Pcp != PbitNone {
+			action := NewSetPcpAction(f.Pcp)
+			actions.Actions = append(actions.Actions, action)
+		}
+
+		// Add the VLAN PUSH
+		if len(f.PushVlan) != 0 {
+			action := NewPushVlanAction(uint32(f.EtherType))
+			actions.Actions = append(actions.Actions, action)
+			for _, vlan := range f.PushVlan {
+				action = NewSetVlanAction(uint16(vlan))
+				actions.Actions = append(actions.Actions, action)
+			}
+		}
+
+		if f.Action.Output == OutputTypeToController {
+			action := NewOutputAction(0xfffffffd)
+			actions.Actions = append(actions.Actions, action)
+		} else if f.Action.Output == OutputTypeToNetwork {
+			action := NewOutputAction(f.OutPort)
+			actions.Actions = append(actions.Actions, action)
+		} else if f.Action.Output == OutputTypeToGroup {
+			action := NewGroupAction(f.OutPort)
+			actions.Actions = append(actions.Actions, action)
+		}
+		instructions = append(instructions, &instruction)
+	}
+
+	return matchList, instructions
+}
+
+// CreateFlow to create flow
+func CreateFlow(device string, command ofp.OfpFlowModCommand, matches []*ofp.OfpOxmField,
+	instructions []*ofp.OfpInstruction, sf *VoltSubFlow) *ofp.FlowTableUpdate {
+	flowUpdate := ofp.FlowTableUpdate{
+		Id: device,
+		FlowMod: &ofp.OfpFlowMod{
+			Cookie:      sf.Cookie,
+			CookieMask:  sf.CookieMask,
+			TableId:     sf.TableID,
+			Command:     command,
+			IdleTimeout: uint32(0),
+			HardTimeout: uint32(0),
+			Priority:    sf.Priority,
+			BufferId:    DefaultBufferID,
+			OutPort:     DefaultOutPort,
+			OutGroup:    DefaultOutGroup,
+			Flags:       DefaultFlags,
+			Match: &ofp.OfpMatch{
+				Type:      ofp.OfpMatchType_OFPMT_OXM,
+				OxmFields: matches,
+			},
+
+			Instructions: instructions,
+		},
+	}
+	return &flowUpdate
+}
+
+// Processing logic for the VOLT flows. The VOLT flows are different from
+// the normal openflows. Each VOLT flow may break into multiple flows.
+// The order of processing:
+// 1. If the flow has to match more than one VLAN tag, it is broken into
+//    more than one flow.
+// 2. When more than one flow is creatd, the higher layer processing is
+//    broken into the second flow. The first flow includes only the
+//    the processing of first VLAN tag.
+// 3. The a sinle flow is created, the first flow has all the match criteria
+//    and action.
+
+// ProcessVoltFlow to process volt flow
+func ProcessVoltFlow(device string, operation Command, subFlow map[uint64]*VoltSubFlow) []*ofp.FlowTableUpdate {
+	var flows []*ofp.FlowTableUpdate
+	var command ofp.OfpFlowModCommand
+	if operation == CommandAdd {
+		command = ofp.OfpFlowModCommand_OFPFC_ADD
+	} else {
+		command = ofp.OfpFlowModCommand_OFPFC_DELETE_STRICT
+	}
+	for _, sf := range subFlow {
+		logger.Debugw(ctx, "Flow Construction for", log.Fields{"Flow": sf})
+		match, instruction := CreateMatchAndActions(sf)
+		flow := CreateFlow(device, command, match, instruction, sf)
+		logger.Debugw(ctx, "Flow Constructed", log.Fields{"Flow": flow})
+		flows = append(flows, flow)
+	}
+	return flows
+}
+
+func init() {
+	// Setup this package so that it's log level can be modified at run time
+	var err error
+	logger, err = log.RegisterPackage(log.JSON, log.ErrorLevel, log.Fields{})
+	if err != nil {
+		panic(err)
+	}
+}