blob: 94744320c750bdbeea100d1c090de4b3ccb1d8ec [file] [log] [blame]
Zack Williams41513bf2018-07-07 20:08:35 -07001/*
2 * Copyright 2017-present Open Networking Foundation
3
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7
8 * http://www.apache.org/licenses/LICENSE-2.0
9
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
Stephane Barbarie35595062018-02-08 08:34:39 -050016package core
17
18import (
19 "context"
Jeff85139852018-07-17 08:55:58 -070020 "net"
21 "sort"
22
Stephane Barbarie35595062018-02-08 08:34:39 -050023 "github.com/google/gopacket"
24 "github.com/google/gopacket/layers"
25 "github.com/google/gopacket/pcap"
26 "github.com/opencord/voltha/ponsim/v2/common"
27 "github.com/opencord/voltha/protos/go/openflow_13"
28 "github.com/sirupsen/logrus"
Stephane Barbarie35595062018-02-08 08:34:39 -050029)
30
31// TODO: Pass-in the certificate information as a structure parameter
32// TODO: Add certification information
33
34type PonSimDevice struct {
35 Name string `json:name`
36 Port int32 `json:port`
37 Address string `json:address`
38 ExternalIf string `json:external_if`
39 InternalIf string `json:internal_if`
40 Promiscuous bool `json:promiscuous`
41 SnapshotLen int32 `json:snapshot_len`
42 AlarmsOn bool `json:alarm_on`
43 AlarmsFreq int `json:alarm_freq`
44 Counter *PonSimMetricCounter `json:counter`
45
46 //*grpc.GrpcSecurity
47
48 flows []*openflow_13.OfpFlowStats `json:-`
49 ingressHandler *pcap.Handle `json:-`
50 egressHandler *pcap.Handle `json:-`
51 links map[int]map[int]interface{} `json:-`
52}
53
54const (
55 UDP_DST = 1
56 UDP_SRC = 2
57 IPV4_DST = 4
58 VLAN_PCP = 8
59 VLAN_VID = 16
60 IP_PROTO = 32
61 ETH_TYPE = 64
62 IN_PORT = 128
63)
64
65/*
66Start performs common setup operations for a ponsim device
67*/
68func (o *PonSimDevice) Start(ctx context.Context) {
69}
70
71/*
72Stop performs common cleanup operations for a ponsim device
73*/
74func (o *PonSimDevice) Stop(ctx context.Context) {
75}
76
77/*
78GetAddress returns the IP/FQDN for the device
79*/
80func (o *PonSimDevice) GetAddress() string {
81 return o.Address
82}
83
84/*
85GetPort return the port assigned to the device
86*/
87func (o *PonSimDevice) GetPort() int32 {
88 return o.Port
89}
90
91/*
92Forward is responsible of processing incoming data, filtering it and redirecting to the
93intended destination
94*/
95func (o *PonSimDevice) Forward(
96 ctx context.Context,
97 port int,
98 frame gopacket.Packet,
99) error {
100 common.Logger().WithFields(logrus.Fields{
101 "device": o,
102 "port": port,
103 "frame": frame,
104 }).Debug("Forwarding packet")
105
106 var err error
107
108 o.Counter.CountRxFrame(port, len(common.GetEthernetLayer(frame).Payload))
109
110 if egressPort, egressFrame := o.processFrame(ctx, port, frame); egressFrame != nil {
Jonathan Hart32fe8812018-08-21 17:10:12 -0700111 o.SendOut(int(egressPort), egressFrame)
Stephane Barbarie35595062018-02-08 08:34:39 -0500112 } else {
113 common.Logger().WithFields(logrus.Fields{
114 "device": o,
Jonathan Hart32fe8812018-08-21 17:10:12 -0700115 "port": int(egressPort),
Stephane Barbarie35595062018-02-08 08:34:39 -0500116 "frame": egressFrame,
117 }).Error("Failed to properly process frame")
118 }
119
120 return err
121}
122
123/*
Jonathan Hart32fe8812018-08-21 17:10:12 -0700124SendOut send a given frame out the given port
125*/
126func (o *PonSimDevice) SendOut(
127 egressPort int,
128 egressFrame gopacket.Packet,
129) {
130 common.Logger().WithFields(logrus.Fields{
131 "egressPort": egressPort,
132 "egressFrame": egressFrame,
133 }).Debug("Sending packet out port")
134
135 forwarded := 0
136 links := o.links[egressPort]
137
138 if egressPort <= 2 && egressPort > 0 {
139 o.Counter.CountTxFrame(egressPort, len(common.GetEthernetLayer(egressFrame).Payload))
140 }
141
142 for _, link := range links {
143 forwarded++
144
145 common.Logger().WithFields(logrus.Fields{
146 "device": o,
147 "egressPort": egressPort,
148 "egressFrame": egressFrame,
149 }).Debug("Forwarding packet to link")
150
151 link.(func(int, gopacket.Packet))(egressPort, egressFrame)
152 }
153 if forwarded == 0 {
154 common.Logger().WithFields(logrus.Fields{
155 "device": o,
156 "egressPort": egressPort,
157 "egressFrame": egressFrame,
158 }).Warn("Nothing was forwarded")
159 }
160}
161
162/*
Stephane Barbarie35595062018-02-08 08:34:39 -0500163connectNetworkInterfaces opens network interfaces for reading and/or writing packets
164*/
165func (o *PonSimDevice) connectNetworkInterfaces() {
166 common.Logger().WithFields(logrus.Fields{
167 "device": o,
168 }).Debug("Opening network interfaces")
169
170 var err error
171 if o.ingressHandler, err = pcap.OpenLive(
172 o.ExternalIf, o.SnapshotLen, o.Promiscuous, pcap.BlockForever,
173 ); err != nil {
174 common.Logger().WithFields(logrus.Fields{
175 "device": o,
176 "interface": o.ExternalIf,
177 "error": err.Error(),
178 }).Fatal("Unable to open Ingress interface")
179 } else {
180 common.Logger().WithFields(logrus.Fields{
181 "device": o,
182 "interface": o.ExternalIf,
183 }).Info("Opened Ingress interface")
184 }
185
186 if o.egressHandler, err = pcap.OpenLive(
187 o.InternalIf, o.SnapshotLen, o.Promiscuous, pcap.BlockForever,
188 ); err != nil {
189 common.Logger().WithFields(logrus.Fields{
190 "device": o,
191 "interface": o.InternalIf,
192 "error": err.Error(),
193 }).Fatal("Unable to open egress interface")
194 } else {
195 common.Logger().WithFields(logrus.Fields{
196 "device": o,
197 "interface": o.InternalIf,
198 }).Info("Opened egress interface")
199 }
200}
201
202/*
203AddLink assigns a functional operation to a device endpoint
204
205The functional operation is called whenever a packet has been processed
206and the endpoint has been identified as the outgoing interface
207*/
208func (o *PonSimDevice) AddLink(
209 port int,
210 index int,
211 function interface{},
212) error {
213 common.Logger().WithFields(logrus.Fields{
214 "device": o,
215 "port": port,
216 "index": index,
217 }).Debug("Linking port to functional operation")
218
219 if o.links == nil {
220 o.links = make(map[int]map[int]interface{})
221 }
222 if _, ok := o.links[port]; !ok {
223 o.links[port] = make(map[int]interface{})
224 }
225 o.links[port][index] = function
226
227 return nil
228}
229
230/*
231RemoveLink will remove reference a functional operation for a given port and index
232*/
233func (o *PonSimDevice) RemoveLink(
234 port int,
235 index int,
236) error {
237 if _, hasPort := o.links[port]; hasPort {
238 if _, hasIndex := o.links[port][index]; hasIndex {
239 common.Logger().WithFields(logrus.Fields{
240 "device": o,
241 "port": port,
242 "index": index,
243 }).Debug("Removing link functional operation")
244
245 delete(o.links[port], index)
246
247 } else {
248 common.Logger().WithFields(logrus.Fields{
249 "device": o,
250 "port": port,
251 "index": index,
252 }).Warn("No such index for link functional operation")
253
254 }
255 } else {
256 common.Logger().WithFields(logrus.Fields{
257 "device": o,
258 "port": port,
259 "index": index,
260 }).Warn("No such port for functional operation")
261 }
262
263 return nil
264}
265
266/*
267InstallFlows assigns flows to the device in order of priority
268*/
269func (o *PonSimDevice) InstallFlows(
270 ctx context.Context,
271 flows []*openflow_13.OfpFlowStats,
272) error {
273 common.Logger().WithFields(logrus.Fields{
274 "device": o,
275 "flows": flows,
276 }).Debug("Installing flows")
277
278 o.flows = flows
Jeff85139852018-07-17 08:55:58 -0700279 sort.Sort(sort.Reverse(common.SortByPriority(o.flows)))
Stephane Barbarie35595062018-02-08 08:34:39 -0500280
281 common.Logger().WithFields(logrus.Fields{
282 "device": o,
283 }).Debug("Installed sorted flows")
284
285 return nil
286}
287
288/*
289processFrame is responsible for matching or discarding a frame based on the configured flows
290*/
291func (o *PonSimDevice) processFrame(
292 ctx context.Context,
293 port int,
294 frame gopacket.Packet,
295) (uint32, gopacket.Packet) {
296 common.Logger().WithFields(logrus.Fields{
297 "device": o,
298 "port": port,
299 "frame": frame,
300 }).Debug("Processing frame")
301
302 var err error
303 var matchedMask int = 0
304 var currentMask int
305 var highestPriority uint32 = 0
306 var matchedFlow *openflow_13.OfpFlowStats = nil
307
308 common.Logger().WithFields(logrus.Fields{
309 "device": o,
310 }).Debug("Looping through flows")
311
312 for _, flow := range o.flows {
313 common.Logger().WithFields(logrus.Fields{
314 "device": o,
315 "flow": flow,
316 }).Debug("Checking flow")
317
318 if matchedFlow != nil && flow.Priority < highestPriority {
319 common.Logger().WithFields(logrus.Fields{
320 "device": o,
321 "matchedFlow": matchedFlow,
322 "priority": highestPriority,
323 }).Debug("Flow has already been matched")
324 break
325 } else {
326 common.Logger().WithFields(logrus.Fields{
327 "device": o,
328 "matchedFlow": matchedFlow,
329 "priority": flow.Priority,
330 "highestPriority": highestPriority,
331 }).Debug("Flow OR Priority requirements not met")
332 }
333
334 highestPriority = flow.Priority
335 if currentMask, err = o.isMatch(ctx, flow, port, frame); err != nil {
336 common.Logger().WithFields(logrus.Fields{
337 "device": o,
338 "flow": flow,
339 "port": port,
340 "frame": frame,
341 "error": err.Error(),
342 }).Error("Problem while matching flow")
343
344 } else if currentMask > matchedMask {
345 matchedMask = currentMask
346 matchedFlow = flow
347
348 common.Logger().WithFields(logrus.Fields{
349 "device": o,
350 "matchedFlow": flow,
351 "port": port,
352 "frame": frame,
353 "matchedMask": matchedMask,
354 }).Debug("Flow matches")
355 }
356 }
357
358 if matchedFlow != nil {
359 egressPort, egressFrame := o.processActions(ctx, matchedFlow, frame)
360
361 common.Logger().WithFields(logrus.Fields{
362 "device": o,
363 "port": port,
364 "egressPort": egressPort,
365 "egressFrame": egressFrame,
366 }).Debug("Processed actions to matched flow")
367
368 return egressPort, egressFrame
369 } else {
370 common.Logger().WithFields(logrus.Fields{
371 "device": o,
372 "port": port,
373 "frame": frame,
374 "matchedMask": matchedMask,
375 }).Warn("Flow was not successfully matched")
376 }
377
378 return 0, nil
379}
380
381/*
382isMatch traverses the criteria of a flow and identify all matching elements of a frame (if any)
383*/
384func (o *PonSimDevice) isMatch(
385 ctx context.Context,
386 flow *openflow_13.OfpFlowStats,
387 port int,
388 frame gopacket.Packet,
389) (int, error) {
390 matchedMask := 0
391
392 for _, ofbfield := range flow.Match.OxmFields {
393 if ofbfield.GetOxmClass() == openflow_13.OfpOxmClass_OFPXMC_OPENFLOW_BASIC {
394 switch ofbfield.GetOfbField().Type {
395 case openflow_13.OxmOfbFieldTypes_OFPXMT_OFB_IN_PORT:
396 if ofbfield.GetOfbField().GetPort() != uint32(port) {
397 common.Logger().WithFields(logrus.Fields{
398 "device": o,
399 "flow": flow,
400 "expected": ofbfield.GetOfbField().GetPort(),
401 "actual": port,
402 }).Warn("Port does not match")
403 return 0, nil
404 } else {
405 common.Logger().WithFields(logrus.Fields{
406 "device": o,
407 "flow": flow,
408 "expected": ofbfield.GetOfbField().GetPort(),
409 "actual": port,
410 }).Debug("Port matches")
411 }
412 matchedMask |= IN_PORT
413
414 case openflow_13.OxmOfbFieldTypes_OFPXMT_OFB_ETH_TYPE:
415 cmpType := uint32(common.GetEthernetLayer(frame).EthernetType)
416 if dot1q := common.GetDot1QLayer(frame); dot1q != nil {
417 cmpType = uint32(dot1q.Type)
418 }
419 if ofbfield.GetOfbField().GetEthType() != cmpType {
420 common.Logger().WithFields(logrus.Fields{
421 "device": o,
422 "flow": flow,
423 "expected": layers.EthernetType(ofbfield.GetOfbField().GetEthType()),
424 "actual": common.GetEthernetLayer(frame).EthernetType,
425 }).Warn("Frame type does not match")
426 return 0, nil
427 } else {
428 common.Logger().WithFields(logrus.Fields{
429 "device": o,
430 "flow": flow,
431 "expected": layers.EthernetType(ofbfield.GetOfbField().GetEthType()),
432 "actual": common.GetEthernetLayer(frame).EthernetType,
433 }).Debug("Frame type matches")
434 }
435 matchedMask |= ETH_TYPE
436
437 case openflow_13.OxmOfbFieldTypes_OFPXMT_OFB_IP_PROTO:
438 if ofbfield.GetOfbField().GetIpProto() != uint32(common.GetIpLayer(frame).Protocol) {
439 common.Logger().WithFields(logrus.Fields{
440 "device": o,
441 "flow": flow,
442 "expected": ofbfield.GetOfbField().GetIpProto(),
443 "actual": common.GetIpLayer(frame).Protocol,
444 }).Warn("IP protocol does not match")
445 return 0, nil
446 } else {
447 common.Logger().WithFields(logrus.Fields{
448 "device": o,
449 "flow": flow,
450 "expected": ofbfield.GetOfbField().GetIpProto(),
451 "actual": common.GetIpLayer(frame).Protocol,
452 }).Debug("IP protocol matches")
453 }
454 matchedMask |= IP_PROTO
455
456 case openflow_13.OxmOfbFieldTypes_OFPXMT_OFB_VLAN_VID:
457 expectedVlan := ofbfield.GetOfbField().GetVlanVid()
458 dot1q := common.GetDot1QLayer(frame)
459
460 if (expectedVlan&4096 == 0) != (dot1q == nil) {
461 common.Logger().WithFields(logrus.Fields{
462 "device": o,
463 "flow": flow,
464 "expectedVlan": expectedVlan,
465 "vlanBitwise": expectedVlan & 4096,
466 "dot1q": dot1q,
467 }).Warn("VLAN condition not met")
468 return 0, nil
469 }
470 if dot1q != nil {
471 if uint32(dot1q.VLANIdentifier) != (expectedVlan & 4095) {
472 common.Logger().WithFields(logrus.Fields{
473 "device": o,
474 "flow": flow,
475 "expected": expectedVlan,
476 "actual": uint32(dot1q.VLANIdentifier),
477 }).Warn("VLAN VID does not match")
478 return 0, nil
479 } else {
480 common.Logger().WithFields(logrus.Fields{
481 "device": o,
482 "flow": flow,
483 "expected": expectedVlan,
484 "actual": uint32(dot1q.VLANIdentifier),
485 }).Debug("VLAN VID matches")
486 }
487 } else {
488 common.Logger().WithFields(logrus.Fields{
489 "device": o,
490 "flow": flow,
491 }).Warn("VLAN VID missing. Not dot1q encapsulation")
492 }
493 matchedMask |= VLAN_VID
494
495 case openflow_13.OxmOfbFieldTypes_OFPXMT_OFB_VLAN_PCP:
496 if ofbfield.GetOfbField().GetVlanPcp() != uint32(common.GetDot1QLayer(frame).Priority) {
497 common.Logger().WithFields(logrus.Fields{
498 "device": o,
499 "flow": flow,
500 "expected": ofbfield.GetOfbField().GetVlanPcp(),
501 "actual": uint32(common.GetDot1QLayer(frame).Priority),
502 }).Warn("VLAN priority does not match")
503 return 0, nil
504 } else {
505 common.Logger().WithFields(logrus.Fields{
506 "device": o,
507 "flow": flow,
508 "expected": ofbfield.GetOfbField().GetVlanPcp(),
509 "actual": uint32(common.GetDot1QLayer(frame).Priority),
510 }).Debug("VLAN priority matches")
511 }
512 matchedMask |= VLAN_PCP
513
514 case openflow_13.OxmOfbFieldTypes_OFPXMT_OFB_IPV4_DST:
515 dstIpRaw := ofbfield.GetOfbField().GetIpv4Dst()
516 dstIp := net.IPv4(
517 byte((dstIpRaw>>24)&0xFF),
518 byte((dstIpRaw>>16)&0xFF),
519 byte((dstIpRaw>>8)&0xFF),
520 byte(dstIpRaw&0xFF))
521
522 if !dstIp.Equal(common.GetIpLayer(frame).DstIP) {
523 common.Logger().WithFields(logrus.Fields{
524 "device": o,
525 "flow": flow,
526 "expected": dstIp,
527 "actual": common.GetIpLayer(frame).DstIP,
528 }).Warn("IPv4 destination does not match")
529 return 0, nil
530 } else {
531 common.Logger().WithFields(logrus.Fields{
532 "device": o,
533 "flow": flow,
534 "expected": dstIp,
535 "actual": common.GetIpLayer(frame).DstIP,
536 }).Debug("IPv4 destination matches")
537
538 }
539 matchedMask |= IPV4_DST
540
541 case openflow_13.OxmOfbFieldTypes_OFPXMT_OFB_UDP_SRC:
542 if ofbfield.GetOfbField().GetUdpSrc() != uint32(common.GetUdpLayer(frame).SrcPort) {
543 common.Logger().WithFields(logrus.Fields{
544 "device": o,
545 "flow": flow,
546 "expected": ofbfield.GetOfbField().GetUdpSrc(),
547 "actual": common.GetUdpLayer(frame).SrcPort,
548 }).Warn("UDP source port does not match")
549 return 0, nil
550 } else {
551 common.Logger().WithFields(logrus.Fields{
552 "device": o,
553 "flow": flow,
554 "expected": ofbfield.GetOfbField().GetUdpSrc(),
555 "actual": common.GetUdpLayer(frame).SrcPort,
556 }).Debug("UDP source port matches")
557 }
558 matchedMask |= UDP_SRC
559
560 case openflow_13.OxmOfbFieldTypes_OFPXMT_OFB_UDP_DST:
561 if ofbfield.GetOfbField().GetUdpDst() != uint32(common.GetUdpLayer(frame).DstPort) {
562 common.Logger().WithFields(logrus.Fields{
563 "device": o,
564 "flow": flow,
565 "expected": ofbfield.GetOfbField().GetUdpDst(),
566 "actual": common.GetUdpLayer(frame).DstPort,
567 }).Warn("UDP destination port does not match")
568 return 0, nil
569 } else {
570 common.Logger().WithFields(logrus.Fields{
571 "device": o,
572 "flow": flow,
573 "expected": ofbfield.GetOfbField().GetUdpDst(),
574 "actual": common.GetUdpLayer(frame).DstPort,
575 }).Debug("UDP destination port does matches")
576 }
577 matchedMask |= UDP_DST
578
579 case openflow_13.OxmOfbFieldTypes_OFPXMT_OFB_METADATA:
580 common.Logger().WithFields(logrus.Fields{
581 "device": o,
582 "flow": flow,
583 }).Warn("Skipping metadata")
584 continue
585
586 default:
587 common.Logger().WithFields(logrus.Fields{
588 "device": o,
589 "flow": flow,
590 "type": ofbfield.GetOfbField().Type,
591 }).Warn("Field type not implemented")
592 }
593 }
594 }
595 return matchedMask, nil
596}
597
598/*
599processActions applies transformation instructions to a frame that met all the flow criteria
600*/
601func (o *PonSimDevice) processActions(
602 ctx context.Context,
603 flow *openflow_13.OfpFlowStats,
604 frame gopacket.Packet,
605) (uint32, gopacket.Packet) {
606 var egressPort uint32
607 var retFrame gopacket.Packet = frame
608
609 common.Logger().WithFields(logrus.Fields{
610 "device": o,
611 "flow": flow,
612 "frame": retFrame,
613 }).Info("Processing actions")
614
615 for _, instruction := range flow.Instructions {
616 common.Logger().WithFields(logrus.Fields{
617 "device": o,
618 "flow": flow,
619 "frame": retFrame,
620 "instruction": instruction,
621 }).Debug("Processing actions - Instruction entry")
622 if instruction.Type == uint32(openflow_13.OfpInstructionType_OFPIT_APPLY_ACTIONS) {
623 for _, action := range instruction.GetActions().GetActions() {
624 common.Logger().WithFields(logrus.Fields{
625 "device": o,
626 "flow": flow,
627 "frame": retFrame,
628 "action": action,
629 "actionType": action.Type,
630 }).Debug("Processing actions - Action entry")
631
632 switch action.Type {
633 case openflow_13.OfpActionType_OFPAT_OUTPUT:
634 common.Logger().WithFields(logrus.Fields{
635 "device": o,
636 "flow": flow,
637 "frame": retFrame,
638 }).Debug("Processing action OFPAT output")
639 egressPort = action.GetOutput().Port
640
641 case openflow_13.OfpActionType_OFPAT_POP_VLAN:
642 common.Logger().WithFields(logrus.Fields{
643 "device": o,
644 "flow": flow,
645 "frame": retFrame,
646 }).Debug("Processing action OFPAT POP VLAN")
647 if shim := common.GetDot1QLayer(retFrame); shim != nil {
648 if eth := common.GetEthernetLayer(retFrame); eth != nil {
649 ethernetLayer := &layers.Ethernet{
650 SrcMAC: eth.SrcMAC,
651 DstMAC: eth.DstMAC,
652 EthernetType: shim.Type,
653 }
654 buffer := gopacket.NewSerializeBuffer()
655 gopacket.SerializeLayers(buffer, gopacket.SerializeOptions{},
656 ethernetLayer,
657 gopacket.Payload(shim.Payload),
658 )
659 retFrame = gopacket.NewPacket(
660 buffer.Bytes(),
661 layers.LayerTypeEthernet,
662 gopacket.Default,
663 )
664 } else {
665 common.Logger().WithFields(logrus.Fields{
666 "device": o,
667 "flow": flow,
668 "frame": retFrame,
669 }).Warn("No ETH found while processing POP VLAN action")
670 }
671 } else {
672 common.Logger().WithFields(logrus.Fields{
673 "device": o,
674 "flow": flow,
675 "frame": retFrame,
676 }).Warn("No DOT1Q found while processing POP VLAN action")
677 }
678 case openflow_13.OfpActionType_OFPAT_PUSH_VLAN:
679 if eth := common.GetEthernetLayer(retFrame); eth != nil {
680 ethernetLayer := &layers.Ethernet{
681 SrcMAC: eth.SrcMAC,
682 DstMAC: eth.DstMAC,
683 EthernetType: layers.EthernetType(action.GetPush().GetEthertype()),
684 }
685 dot1qLayer := &layers.Dot1Q{
686 Type: eth.EthernetType,
687 }
688
689 buffer := gopacket.NewSerializeBuffer()
690 gopacket.SerializeLayers(
691 buffer,
692 gopacket.SerializeOptions{
693 FixLengths: false,
694 },
695 ethernetLayer,
696 dot1qLayer,
697 gopacket.Payload(eth.Payload),
698 )
699 retFrame = gopacket.NewPacket(
700 buffer.Bytes(),
701 layers.LayerTypeEthernet,
702 gopacket.Default,
703 )
704 } else {
705 common.Logger().WithFields(logrus.Fields{
706 "device": o,
707 "flow": flow,
708 "frame": retFrame,
709 }).Warn("No ETH found while processing PUSH VLAN action")
710 }
711 case openflow_13.OfpActionType_OFPAT_SET_FIELD:
712 common.Logger().WithFields(logrus.Fields{
713 "device": o,
714 "flow": flow,
715 "frame": retFrame,
716 }).Debug("Processing action OFPAT SET FIELD")
717 if action.GetSetField().GetField().GetOxmClass() ==
718 openflow_13.OfpOxmClass_OFPXMC_OPENFLOW_BASIC {
719 field := action.GetSetField().GetField().GetOfbField()
720
721 switch field.Type {
722 case openflow_13.OxmOfbFieldTypes_OFPXMT_OFB_VLAN_VID:
723 common.Logger().WithFields(logrus.Fields{
724 "device": o,
725 "flow": flow,
726 "frame": retFrame,
727 }).Debug("Processing action OFPAT SET FIELD - VLAN VID")
728 if shim := common.GetDot1QLayer(retFrame); shim != nil {
729 eth := common.GetEthernetLayer(retFrame)
730 buffer := gopacket.NewSerializeBuffer()
731
732 var dot1qLayer *layers.Dot1Q
733 var ethernetLayer *layers.Ethernet
734 ethernetLayer = &layers.Ethernet{
735 SrcMAC: eth.SrcMAC,
736 DstMAC: eth.DstMAC,
737 EthernetType: eth.EthernetType,
738 }
739
740 dot1qLayer = &layers.Dot1Q{
741 Type: shim.Type,
742 VLANIdentifier: uint16(field.GetVlanVid() & 4095),
743 }
744
745 gopacket.SerializeLayers(
746 buffer,
747 gopacket.SerializeOptions{},
748 ethernetLayer,
749 dot1qLayer,
750 gopacket.Payload(shim.LayerPayload()),
751 )
752 retFrame = gopacket.NewPacket(
753 buffer.Bytes(),
754 layers.LayerTypeEthernet,
755 gopacket.Default,
756 )
757
758 common.Logger().WithFields(logrus.Fields{
759 "device": o,
760 "flow": flow,
761 "frame": retFrame,
762 "frameDump": retFrame.Dump(),
763 "vlanVid": shim.VLANIdentifier,
764 }).Info("Setting DOT1Q VLAN VID")
765 } else {
766 common.Logger().WithFields(logrus.Fields{
767 "device": o,
768 "flow": flow,
769 "frame": retFrame,
770 }).Warn("No DOT1Q found while setting VLAN VID")
771 }
772
773 case openflow_13.OxmOfbFieldTypes_OFPXMT_OFB_VLAN_PCP:
774 common.Logger().WithFields(logrus.Fields{
775 "device": o,
776 "flow": flow,
777 "frame": retFrame,
778 }).Debug("Processing action OFPAT SET FIELD - VLAN PCP")
779 if shim := common.GetDot1QLayer(retFrame); shim != nil {
780 shim.Priority = uint8(field.GetVlanPcp())
781 common.Logger().WithFields(logrus.Fields{
782 "device": o,
783 "flow": flow,
784 "frame": retFrame,
785 "priority": shim.Priority,
786 }).Info("Setting DOT1Q VLAN PCP")
787 } else {
788 common.Logger().WithFields(logrus.Fields{
789 "device": o,
790 "flow": flow,
791 "frame": retFrame,
792 }).Warn("No DOT1Q found while setting VLAN PCP")
793 }
794 default:
795 common.Logger().WithFields(logrus.Fields{
796 "device": o,
797 "flow": flow,
798 "frame": retFrame,
799 "type": field.Type,
800 }).Warn("Set field not implemented for this type")
801 }
802 } else {
803 common.Logger().WithFields(logrus.Fields{
804 "device": o,
805 "flow": flow,
806 "frame": retFrame,
807 }).Warn("Field not of type OF-BASIC")
808 }
809 default:
810 common.Logger().WithFields(logrus.Fields{
811 "device": o,
812 "flow": flow,
813 "frame": retFrame,
814 "type": action.Type,
815 }).Warn("Action type not implemented")
816 }
817 }
818 }
819 }
820
821 common.Logger().WithFields(logrus.Fields{
822 "device": o,
823 "flow": flow,
824 "egressPort": egressPort,
825 "retFrame": retFrame,
826 }).Debug("Processed actions")
827
828 return egressPort, retFrame
829}