VOL-291 : PON simulator refactoring for cluster integration
- Added ponsim build target in Makefile
- Added new option to vcore to select comm type with ponsim
- Modified all proto files to include destination go package
Amendments:
- Clean up based on review comments
- Properly close GRPC connections in ponsim_olt adapter
- Added voltha namespace to some k8s templates
Change-Id: I2f349fa7b3550a8a8cc8fc676cc896f33fbb9372
diff --git a/ponsim/v2/core/ponsim_device.go b/ponsim/v2/core/ponsim_device.go
new file mode 100644
index 0000000..c13d003
--- /dev/null
+++ b/ponsim/v2/core/ponsim_device.go
@@ -0,0 +1,796 @@
+package core
+
+import (
+ "context"
+ "github.com/google/gopacket"
+ "github.com/google/gopacket/layers"
+ "github.com/google/gopacket/pcap"
+ "github.com/opencord/voltha/ponsim/v2/common"
+ "github.com/opencord/voltha/protos/go/openflow_13"
+ "github.com/sirupsen/logrus"
+ "net"
+ "sort"
+)
+
+// TODO: Pass-in the certificate information as a structure parameter
+// TODO: Add certification information
+
+type PonSimDevice struct {
+ Name string `json:name`
+ Port int32 `json:port`
+ Address string `json:address`
+ ExternalIf string `json:external_if`
+ InternalIf string `json:internal_if`
+ Promiscuous bool `json:promiscuous`
+ SnapshotLen int32 `json:snapshot_len`
+ AlarmsOn bool `json:alarm_on`
+ AlarmsFreq int `json:alarm_freq`
+ Counter *PonSimMetricCounter `json:counter`
+
+ //*grpc.GrpcSecurity
+
+ flows []*openflow_13.OfpFlowStats `json:-`
+ ingressHandler *pcap.Handle `json:-`
+ egressHandler *pcap.Handle `json:-`
+ links map[int]map[int]interface{} `json:-`
+}
+
+const (
+ UDP_DST = 1
+ UDP_SRC = 2
+ IPV4_DST = 4
+ VLAN_PCP = 8
+ VLAN_VID = 16
+ IP_PROTO = 32
+ ETH_TYPE = 64
+ IN_PORT = 128
+)
+
+/*
+Start performs common setup operations for a ponsim device
+*/
+func (o *PonSimDevice) Start(ctx context.Context) {
+}
+
+/*
+Stop performs common cleanup operations for a ponsim device
+*/
+func (o *PonSimDevice) Stop(ctx context.Context) {
+}
+
+/*
+GetAddress returns the IP/FQDN for the device
+*/
+func (o *PonSimDevice) GetAddress() string {
+ return o.Address
+}
+
+/*
+GetPort return the port assigned to the device
+*/
+func (o *PonSimDevice) GetPort() int32 {
+ return o.Port
+}
+
+/*
+Forward is responsible of processing incoming data, filtering it and redirecting to the
+intended destination
+*/
+func (o *PonSimDevice) Forward(
+ ctx context.Context,
+ port int,
+ frame gopacket.Packet,
+) error {
+ common.Logger().WithFields(logrus.Fields{
+ "device": o,
+ "port": port,
+ "frame": frame,
+ }).Debug("Forwarding packet")
+
+ var err error
+
+ o.Counter.CountRxFrame(port, len(common.GetEthernetLayer(frame).Payload))
+
+ if egressPort, egressFrame := o.processFrame(ctx, port, frame); egressFrame != nil {
+ forwarded := 0
+ links := o.links[int(egressPort)]
+
+ o.Counter.CountTxFrame(int(egressPort), len(common.GetEthernetLayer(egressFrame).Payload))
+
+ for _, link := range links {
+ forwarded += 1
+
+ common.Logger().WithFields(logrus.Fields{
+ "device": o,
+ "egressPort": port,
+ "egressFrame": egressFrame,
+ }).Debug("Forwarding packet to link")
+
+ link.(func(int, gopacket.Packet))(int(egressPort), egressFrame)
+ }
+ if forwarded == 0 {
+ common.Logger().WithFields(logrus.Fields{
+ "device": o,
+ "port": port,
+ "frame": frame,
+ }).Warn("Nothing was forwarded")
+ }
+ } else {
+ common.Logger().WithFields(logrus.Fields{
+ "device": o,
+ "port": egressPort,
+ "frame": egressFrame,
+ }).Error("Failed to properly process frame")
+ }
+
+ return err
+}
+
+/*
+connectNetworkInterfaces opens network interfaces for reading and/or writing packets
+*/
+func (o *PonSimDevice) connectNetworkInterfaces() {
+ common.Logger().WithFields(logrus.Fields{
+ "device": o,
+ }).Debug("Opening network interfaces")
+
+ var err error
+ if o.ingressHandler, err = pcap.OpenLive(
+ o.ExternalIf, o.SnapshotLen, o.Promiscuous, pcap.BlockForever,
+ ); err != nil {
+ common.Logger().WithFields(logrus.Fields{
+ "device": o,
+ "interface": o.ExternalIf,
+ "error": err.Error(),
+ }).Fatal("Unable to open Ingress interface")
+ } else {
+ common.Logger().WithFields(logrus.Fields{
+ "device": o,
+ "interface": o.ExternalIf,
+ }).Info("Opened Ingress interface")
+ }
+
+ if o.egressHandler, err = pcap.OpenLive(
+ o.InternalIf, o.SnapshotLen, o.Promiscuous, pcap.BlockForever,
+ ); err != nil {
+ common.Logger().WithFields(logrus.Fields{
+ "device": o,
+ "interface": o.InternalIf,
+ "error": err.Error(),
+ }).Fatal("Unable to open egress interface")
+ } else {
+ common.Logger().WithFields(logrus.Fields{
+ "device": o,
+ "interface": o.InternalIf,
+ }).Info("Opened egress interface")
+ }
+}
+
+/*
+AddLink assigns a functional operation to a device endpoint
+
+The functional operation is called whenever a packet has been processed
+and the endpoint has been identified as the outgoing interface
+*/
+func (o *PonSimDevice) AddLink(
+ port int,
+ index int,
+ function interface{},
+) error {
+ common.Logger().WithFields(logrus.Fields{
+ "device": o,
+ "port": port,
+ "index": index,
+ }).Debug("Linking port to functional operation")
+
+ if o.links == nil {
+ o.links = make(map[int]map[int]interface{})
+ }
+ if _, ok := o.links[port]; !ok {
+ o.links[port] = make(map[int]interface{})
+ }
+ o.links[port][index] = function
+
+ return nil
+}
+
+/*
+RemoveLink will remove reference a functional operation for a given port and index
+*/
+func (o *PonSimDevice) RemoveLink(
+ port int,
+ index int,
+) error {
+ if _, hasPort := o.links[port]; hasPort {
+ if _, hasIndex := o.links[port][index]; hasIndex {
+ common.Logger().WithFields(logrus.Fields{
+ "device": o,
+ "port": port,
+ "index": index,
+ }).Debug("Removing link functional operation")
+
+ delete(o.links[port], index)
+
+ } else {
+ common.Logger().WithFields(logrus.Fields{
+ "device": o,
+ "port": port,
+ "index": index,
+ }).Warn("No such index for link functional operation")
+
+ }
+ } else {
+ common.Logger().WithFields(logrus.Fields{
+ "device": o,
+ "port": port,
+ "index": index,
+ }).Warn("No such port for functional operation")
+ }
+
+ return nil
+}
+
+/*
+InstallFlows assigns flows to the device in order of priority
+*/
+func (o *PonSimDevice) InstallFlows(
+ ctx context.Context,
+ flows []*openflow_13.OfpFlowStats,
+) error {
+ common.Logger().WithFields(logrus.Fields{
+ "device": o,
+ "flows": flows,
+ }).Debug("Installing flows")
+
+ o.flows = flows
+ sort.Sort(common.SortByPriority(o.flows))
+
+ common.Logger().WithFields(logrus.Fields{
+ "device": o,
+ }).Debug("Installed sorted flows")
+
+ return nil
+}
+
+/*
+processFrame is responsible for matching or discarding a frame based on the configured flows
+*/
+func (o *PonSimDevice) processFrame(
+ ctx context.Context,
+ port int,
+ frame gopacket.Packet,
+) (uint32, gopacket.Packet) {
+ common.Logger().WithFields(logrus.Fields{
+ "device": o,
+ "port": port,
+ "frame": frame,
+ }).Debug("Processing frame")
+
+ var err error
+ var matchedMask int = 0
+ var currentMask int
+ var highestPriority uint32 = 0
+ var matchedFlow *openflow_13.OfpFlowStats = nil
+
+ common.Logger().WithFields(logrus.Fields{
+ "device": o,
+ }).Debug("Looping through flows")
+
+ for _, flow := range o.flows {
+ common.Logger().WithFields(logrus.Fields{
+ "device": o,
+ "flow": flow,
+ }).Debug("Checking flow")
+
+ if matchedFlow != nil && flow.Priority < highestPriority {
+ common.Logger().WithFields(logrus.Fields{
+ "device": o,
+ "matchedFlow": matchedFlow,
+ "priority": highestPriority,
+ }).Debug("Flow has already been matched")
+ break
+ } else {
+ common.Logger().WithFields(logrus.Fields{
+ "device": o,
+ "matchedFlow": matchedFlow,
+ "priority": flow.Priority,
+ "highestPriority": highestPriority,
+ }).Debug("Flow OR Priority requirements not met")
+ }
+
+ highestPriority = flow.Priority
+ if currentMask, err = o.isMatch(ctx, flow, port, frame); err != nil {
+ common.Logger().WithFields(logrus.Fields{
+ "device": o,
+ "flow": flow,
+ "port": port,
+ "frame": frame,
+ "error": err.Error(),
+ }).Error("Problem while matching flow")
+
+ } else if currentMask > matchedMask {
+ matchedMask = currentMask
+ matchedFlow = flow
+
+ common.Logger().WithFields(logrus.Fields{
+ "device": o,
+ "matchedFlow": flow,
+ "port": port,
+ "frame": frame,
+ "matchedMask": matchedMask,
+ }).Debug("Flow matches")
+ }
+ }
+
+ if matchedFlow != nil {
+ egressPort, egressFrame := o.processActions(ctx, matchedFlow, frame)
+
+ common.Logger().WithFields(logrus.Fields{
+ "device": o,
+ "port": port,
+ "egressPort": egressPort,
+ "egressFrame": egressFrame,
+ }).Debug("Processed actions to matched flow")
+
+ return egressPort, egressFrame
+ } else {
+ common.Logger().WithFields(logrus.Fields{
+ "device": o,
+ "port": port,
+ "frame": frame,
+ "matchedMask": matchedMask,
+ }).Warn("Flow was not successfully matched")
+ }
+
+ return 0, nil
+}
+
+/*
+isMatch traverses the criteria of a flow and identify all matching elements of a frame (if any)
+*/
+func (o *PonSimDevice) isMatch(
+ ctx context.Context,
+ flow *openflow_13.OfpFlowStats,
+ port int,
+ frame gopacket.Packet,
+) (int, error) {
+ matchedMask := 0
+
+ for _, ofbfield := range flow.Match.OxmFields {
+ if ofbfield.GetOxmClass() == openflow_13.OfpOxmClass_OFPXMC_OPENFLOW_BASIC {
+ switch ofbfield.GetOfbField().Type {
+ case openflow_13.OxmOfbFieldTypes_OFPXMT_OFB_IN_PORT:
+ if ofbfield.GetOfbField().GetPort() != uint32(port) {
+ common.Logger().WithFields(logrus.Fields{
+ "device": o,
+ "flow": flow,
+ "expected": ofbfield.GetOfbField().GetPort(),
+ "actual": port,
+ }).Warn("Port does not match")
+ return 0, nil
+ } else {
+ common.Logger().WithFields(logrus.Fields{
+ "device": o,
+ "flow": flow,
+ "expected": ofbfield.GetOfbField().GetPort(),
+ "actual": port,
+ }).Debug("Port matches")
+ }
+ matchedMask |= IN_PORT
+
+ case openflow_13.OxmOfbFieldTypes_OFPXMT_OFB_ETH_TYPE:
+ cmpType := uint32(common.GetEthernetLayer(frame).EthernetType)
+ if dot1q := common.GetDot1QLayer(frame); dot1q != nil {
+ cmpType = uint32(dot1q.Type)
+ }
+ if ofbfield.GetOfbField().GetEthType() != cmpType {
+ common.Logger().WithFields(logrus.Fields{
+ "device": o,
+ "flow": flow,
+ "expected": layers.EthernetType(ofbfield.GetOfbField().GetEthType()),
+ "actual": common.GetEthernetLayer(frame).EthernetType,
+ }).Warn("Frame type does not match")
+ return 0, nil
+ } else {
+ common.Logger().WithFields(logrus.Fields{
+ "device": o,
+ "flow": flow,
+ "expected": layers.EthernetType(ofbfield.GetOfbField().GetEthType()),
+ "actual": common.GetEthernetLayer(frame).EthernetType,
+ }).Debug("Frame type matches")
+ }
+ matchedMask |= ETH_TYPE
+
+ case openflow_13.OxmOfbFieldTypes_OFPXMT_OFB_IP_PROTO:
+ if ofbfield.GetOfbField().GetIpProto() != uint32(common.GetIpLayer(frame).Protocol) {
+ common.Logger().WithFields(logrus.Fields{
+ "device": o,
+ "flow": flow,
+ "expected": ofbfield.GetOfbField().GetIpProto(),
+ "actual": common.GetIpLayer(frame).Protocol,
+ }).Warn("IP protocol does not match")
+ return 0, nil
+ } else {
+ common.Logger().WithFields(logrus.Fields{
+ "device": o,
+ "flow": flow,
+ "expected": ofbfield.GetOfbField().GetIpProto(),
+ "actual": common.GetIpLayer(frame).Protocol,
+ }).Debug("IP protocol matches")
+ }
+ matchedMask |= IP_PROTO
+
+ case openflow_13.OxmOfbFieldTypes_OFPXMT_OFB_VLAN_VID:
+ expectedVlan := ofbfield.GetOfbField().GetVlanVid()
+ dot1q := common.GetDot1QLayer(frame)
+
+ if (expectedVlan&4096 == 0) != (dot1q == nil) {
+ common.Logger().WithFields(logrus.Fields{
+ "device": o,
+ "flow": flow,
+ "expectedVlan": expectedVlan,
+ "vlanBitwise": expectedVlan & 4096,
+ "dot1q": dot1q,
+ }).Warn("VLAN condition not met")
+ return 0, nil
+ }
+ if dot1q != nil {
+ if uint32(dot1q.VLANIdentifier) != (expectedVlan & 4095) {
+ common.Logger().WithFields(logrus.Fields{
+ "device": o,
+ "flow": flow,
+ "expected": expectedVlan,
+ "actual": uint32(dot1q.VLANIdentifier),
+ }).Warn("VLAN VID does not match")
+ return 0, nil
+ } else {
+ common.Logger().WithFields(logrus.Fields{
+ "device": o,
+ "flow": flow,
+ "expected": expectedVlan,
+ "actual": uint32(dot1q.VLANIdentifier),
+ }).Debug("VLAN VID matches")
+ }
+ } else {
+ common.Logger().WithFields(logrus.Fields{
+ "device": o,
+ "flow": flow,
+ }).Warn("VLAN VID missing. Not dot1q encapsulation")
+ }
+ matchedMask |= VLAN_VID
+
+ case openflow_13.OxmOfbFieldTypes_OFPXMT_OFB_VLAN_PCP:
+ if ofbfield.GetOfbField().GetVlanPcp() != uint32(common.GetDot1QLayer(frame).Priority) {
+ common.Logger().WithFields(logrus.Fields{
+ "device": o,
+ "flow": flow,
+ "expected": ofbfield.GetOfbField().GetVlanPcp(),
+ "actual": uint32(common.GetDot1QLayer(frame).Priority),
+ }).Warn("VLAN priority does not match")
+ return 0, nil
+ } else {
+ common.Logger().WithFields(logrus.Fields{
+ "device": o,
+ "flow": flow,
+ "expected": ofbfield.GetOfbField().GetVlanPcp(),
+ "actual": uint32(common.GetDot1QLayer(frame).Priority),
+ }).Debug("VLAN priority matches")
+ }
+ matchedMask |= VLAN_PCP
+
+ case openflow_13.OxmOfbFieldTypes_OFPXMT_OFB_IPV4_DST:
+ dstIpRaw := ofbfield.GetOfbField().GetIpv4Dst()
+ dstIp := net.IPv4(
+ byte((dstIpRaw>>24)&0xFF),
+ byte((dstIpRaw>>16)&0xFF),
+ byte((dstIpRaw>>8)&0xFF),
+ byte(dstIpRaw&0xFF))
+
+ if !dstIp.Equal(common.GetIpLayer(frame).DstIP) {
+ common.Logger().WithFields(logrus.Fields{
+ "device": o,
+ "flow": flow,
+ "expected": dstIp,
+ "actual": common.GetIpLayer(frame).DstIP,
+ }).Warn("IPv4 destination does not match")
+ return 0, nil
+ } else {
+ common.Logger().WithFields(logrus.Fields{
+ "device": o,
+ "flow": flow,
+ "expected": dstIp,
+ "actual": common.GetIpLayer(frame).DstIP,
+ }).Debug("IPv4 destination matches")
+
+ }
+ matchedMask |= IPV4_DST
+
+ case openflow_13.OxmOfbFieldTypes_OFPXMT_OFB_UDP_SRC:
+ if ofbfield.GetOfbField().GetUdpSrc() != uint32(common.GetUdpLayer(frame).SrcPort) {
+ common.Logger().WithFields(logrus.Fields{
+ "device": o,
+ "flow": flow,
+ "expected": ofbfield.GetOfbField().GetUdpSrc(),
+ "actual": common.GetUdpLayer(frame).SrcPort,
+ }).Warn("UDP source port does not match")
+ return 0, nil
+ } else {
+ common.Logger().WithFields(logrus.Fields{
+ "device": o,
+ "flow": flow,
+ "expected": ofbfield.GetOfbField().GetUdpSrc(),
+ "actual": common.GetUdpLayer(frame).SrcPort,
+ }).Debug("UDP source port matches")
+ }
+ matchedMask |= UDP_SRC
+
+ case openflow_13.OxmOfbFieldTypes_OFPXMT_OFB_UDP_DST:
+ if ofbfield.GetOfbField().GetUdpDst() != uint32(common.GetUdpLayer(frame).DstPort) {
+ common.Logger().WithFields(logrus.Fields{
+ "device": o,
+ "flow": flow,
+ "expected": ofbfield.GetOfbField().GetUdpDst(),
+ "actual": common.GetUdpLayer(frame).DstPort,
+ }).Warn("UDP destination port does not match")
+ return 0, nil
+ } else {
+ common.Logger().WithFields(logrus.Fields{
+ "device": o,
+ "flow": flow,
+ "expected": ofbfield.GetOfbField().GetUdpDst(),
+ "actual": common.GetUdpLayer(frame).DstPort,
+ }).Debug("UDP destination port does matches")
+ }
+ matchedMask |= UDP_DST
+
+ case openflow_13.OxmOfbFieldTypes_OFPXMT_OFB_METADATA:
+ common.Logger().WithFields(logrus.Fields{
+ "device": o,
+ "flow": flow,
+ }).Warn("Skipping metadata")
+ continue
+
+ default:
+ common.Logger().WithFields(logrus.Fields{
+ "device": o,
+ "flow": flow,
+ "type": ofbfield.GetOfbField().Type,
+ }).Warn("Field type not implemented")
+ }
+ }
+ }
+ return matchedMask, nil
+}
+
+/*
+processActions applies transformation instructions to a frame that met all the flow criteria
+*/
+func (o *PonSimDevice) processActions(
+ ctx context.Context,
+ flow *openflow_13.OfpFlowStats,
+ frame gopacket.Packet,
+) (uint32, gopacket.Packet) {
+ var egressPort uint32
+ var retFrame gopacket.Packet = frame
+
+ common.Logger().WithFields(logrus.Fields{
+ "device": o,
+ "flow": flow,
+ "frame": retFrame,
+ }).Info("Processing actions")
+
+ for _, instruction := range flow.Instructions {
+ common.Logger().WithFields(logrus.Fields{
+ "device": o,
+ "flow": flow,
+ "frame": retFrame,
+ "instruction": instruction,
+ }).Debug("Processing actions - Instruction entry")
+ if instruction.Type == uint32(openflow_13.OfpInstructionType_OFPIT_APPLY_ACTIONS) {
+ for _, action := range instruction.GetActions().GetActions() {
+ common.Logger().WithFields(logrus.Fields{
+ "device": o,
+ "flow": flow,
+ "frame": retFrame,
+ "action": action,
+ "actionType": action.Type,
+ }).Debug("Processing actions - Action entry")
+
+ switch action.Type {
+ case openflow_13.OfpActionType_OFPAT_OUTPUT:
+ common.Logger().WithFields(logrus.Fields{
+ "device": o,
+ "flow": flow,
+ "frame": retFrame,
+ }).Debug("Processing action OFPAT output")
+ egressPort = action.GetOutput().Port
+
+ case openflow_13.OfpActionType_OFPAT_POP_VLAN:
+ common.Logger().WithFields(logrus.Fields{
+ "device": o,
+ "flow": flow,
+ "frame": retFrame,
+ }).Debug("Processing action OFPAT POP VLAN")
+ if shim := common.GetDot1QLayer(retFrame); shim != nil {
+ if eth := common.GetEthernetLayer(retFrame); eth != nil {
+ ethernetLayer := &layers.Ethernet{
+ SrcMAC: eth.SrcMAC,
+ DstMAC: eth.DstMAC,
+ EthernetType: shim.Type,
+ }
+ buffer := gopacket.NewSerializeBuffer()
+ gopacket.SerializeLayers(buffer, gopacket.SerializeOptions{},
+ ethernetLayer,
+ gopacket.Payload(shim.Payload),
+ )
+ retFrame = gopacket.NewPacket(
+ buffer.Bytes(),
+ layers.LayerTypeEthernet,
+ gopacket.Default,
+ )
+ } else {
+ common.Logger().WithFields(logrus.Fields{
+ "device": o,
+ "flow": flow,
+ "frame": retFrame,
+ }).Warn("No ETH found while processing POP VLAN action")
+ }
+ } else {
+ common.Logger().WithFields(logrus.Fields{
+ "device": o,
+ "flow": flow,
+ "frame": retFrame,
+ }).Warn("No DOT1Q found while processing POP VLAN action")
+ }
+ case openflow_13.OfpActionType_OFPAT_PUSH_VLAN:
+ if eth := common.GetEthernetLayer(retFrame); eth != nil {
+ ethernetLayer := &layers.Ethernet{
+ SrcMAC: eth.SrcMAC,
+ DstMAC: eth.DstMAC,
+ EthernetType: layers.EthernetType(action.GetPush().GetEthertype()),
+ }
+ dot1qLayer := &layers.Dot1Q{
+ Type: eth.EthernetType,
+ }
+
+ buffer := gopacket.NewSerializeBuffer()
+ gopacket.SerializeLayers(
+ buffer,
+ gopacket.SerializeOptions{
+ FixLengths: false,
+ },
+ ethernetLayer,
+ dot1qLayer,
+ gopacket.Payload(eth.Payload),
+ )
+ retFrame = gopacket.NewPacket(
+ buffer.Bytes(),
+ layers.LayerTypeEthernet,
+ gopacket.Default,
+ )
+ } else {
+ common.Logger().WithFields(logrus.Fields{
+ "device": o,
+ "flow": flow,
+ "frame": retFrame,
+ }).Warn("No ETH found while processing PUSH VLAN action")
+ }
+ case openflow_13.OfpActionType_OFPAT_SET_FIELD:
+ common.Logger().WithFields(logrus.Fields{
+ "device": o,
+ "flow": flow,
+ "frame": retFrame,
+ }).Debug("Processing action OFPAT SET FIELD")
+ if action.GetSetField().GetField().GetOxmClass() ==
+ openflow_13.OfpOxmClass_OFPXMC_OPENFLOW_BASIC {
+ field := action.GetSetField().GetField().GetOfbField()
+
+ switch field.Type {
+ case openflow_13.OxmOfbFieldTypes_OFPXMT_OFB_VLAN_VID:
+ common.Logger().WithFields(logrus.Fields{
+ "device": o,
+ "flow": flow,
+ "frame": retFrame,
+ }).Debug("Processing action OFPAT SET FIELD - VLAN VID")
+ if shim := common.GetDot1QLayer(retFrame); shim != nil {
+ eth := common.GetEthernetLayer(retFrame)
+ buffer := gopacket.NewSerializeBuffer()
+
+ var dot1qLayer *layers.Dot1Q
+ var ethernetLayer *layers.Ethernet
+ ethernetLayer = &layers.Ethernet{
+ SrcMAC: eth.SrcMAC,
+ DstMAC: eth.DstMAC,
+ EthernetType: eth.EthernetType,
+ }
+
+ dot1qLayer = &layers.Dot1Q{
+ Type: shim.Type,
+ VLANIdentifier: uint16(field.GetVlanVid() & 4095),
+ }
+
+ gopacket.SerializeLayers(
+ buffer,
+ gopacket.SerializeOptions{},
+ ethernetLayer,
+ dot1qLayer,
+ gopacket.Payload(shim.LayerPayload()),
+ )
+ retFrame = gopacket.NewPacket(
+ buffer.Bytes(),
+ layers.LayerTypeEthernet,
+ gopacket.Default,
+ )
+
+ common.Logger().WithFields(logrus.Fields{
+ "device": o,
+ "flow": flow,
+ "frame": retFrame,
+ "frameDump": retFrame.Dump(),
+ "vlanVid": shim.VLANIdentifier,
+ }).Info("Setting DOT1Q VLAN VID")
+ } else {
+ common.Logger().WithFields(logrus.Fields{
+ "device": o,
+ "flow": flow,
+ "frame": retFrame,
+ }).Warn("No DOT1Q found while setting VLAN VID")
+ }
+
+ case openflow_13.OxmOfbFieldTypes_OFPXMT_OFB_VLAN_PCP:
+ common.Logger().WithFields(logrus.Fields{
+ "device": o,
+ "flow": flow,
+ "frame": retFrame,
+ }).Debug("Processing action OFPAT SET FIELD - VLAN PCP")
+ if shim := common.GetDot1QLayer(retFrame); shim != nil {
+ shim.Priority = uint8(field.GetVlanPcp())
+ common.Logger().WithFields(logrus.Fields{
+ "device": o,
+ "flow": flow,
+ "frame": retFrame,
+ "priority": shim.Priority,
+ }).Info("Setting DOT1Q VLAN PCP")
+ } else {
+ common.Logger().WithFields(logrus.Fields{
+ "device": o,
+ "flow": flow,
+ "frame": retFrame,
+ }).Warn("No DOT1Q found while setting VLAN PCP")
+ }
+ default:
+ common.Logger().WithFields(logrus.Fields{
+ "device": o,
+ "flow": flow,
+ "frame": retFrame,
+ "type": field.Type,
+ }).Warn("Set field not implemented for this type")
+ }
+ } else {
+ common.Logger().WithFields(logrus.Fields{
+ "device": o,
+ "flow": flow,
+ "frame": retFrame,
+ }).Warn("Field not of type OF-BASIC")
+ }
+ default:
+ common.Logger().WithFields(logrus.Fields{
+ "device": o,
+ "flow": flow,
+ "frame": retFrame,
+ "type": action.Type,
+ }).Warn("Action type not implemented")
+ }
+ }
+ }
+ }
+
+ common.Logger().WithFields(logrus.Fields{
+ "device": o,
+ "flow": flow,
+ "egressPort": egressPort,
+ "retFrame": retFrame,
+ }).Debug("Processed actions")
+
+ return egressPort, retFrame
+}