blob: ff447549a297c34a4ce836383099bda9c0f2ccc8 [file] [log] [blame]
Naveen Sampath04696f72022-06-13 15:19:14 +05301/*
2* Copyright 2022-present Open Networking Foundation
3* Licensed under the Apache License, Version 2.0 (the "License");
4* you may not use this file except in compliance with the License.
5* You may obtain a copy of the License at
6*
7* http://www.apache.org/licenses/LICENSE-2.0
8*
9* Unless required by applicable law or agreed to in writing, software
10* distributed under the License is distributed on an "AS IS" BASIS,
11* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12* See the License for the specific language governing permissions and
13* limitations under the License.
14*/
15
16package of
17
18import (
19 "context"
20 "net"
21 "strconv"
22
23 "github.com/google/gopacket/layers"
24
25 "github.com/opencord/voltha-lib-go/v7/pkg/flows"
Tinoj Joseph1d108322022-07-13 10:07:39 +053026 "voltha-go-controller/log"
Naveen Sampath04696f72022-06-13 15:19:14 +053027 ofp "github.com/opencord/voltha-protos/v5/go/openflow_13"
28 //"github.com/opencord/voltha-protos/v5/go/voltha"
29)
30
31// PbitType type
32type PbitType uint16
33
34// TODO: Port related constants - OF specifies a different value
35// for controller. Need to make sure this is correct
36const (
37 ControllerPort uint32 = 0xfffffffd
38 PbitMatchNone PbitType = 8
39 PbitMatchAll PbitType = 0xFF
40)
41
42var logger log.CLogger
Naveen Sampath04696f72022-06-13 15:19:14 +053043var ctx = context.TODO()
44
45// ----------------------------------------------------------
46// Cookie related specifications and utilities
47// ----------------------------------------------------------
48// Though the openflow does not utilize cookies as unique identities of
49// flows, we use cookies as identities in the application. The same
50// may also be used in the VOLTHA if so desired to reduce the complexity
51// of management of flows. In terms of how the cookie is set and is
52// ensured to be unique is:
53// Cookie is a 64 bit value. The first 32 bits are set to the port-id
54// All rules set at the device level are associated with NNI. All other
55// flows, both ingress and egress are associated with the access port.
56// The last 32 bits are used to uniquely identifies flows of a port.
57const (
58 // The flow masks are used to set the MSB of the lower
59 // 32 bits of cookie
60
61 // UsFlowMask constant
62 UsFlowMask uint64 = 0x8000
63 // DsFlowMask constant
64 DsFlowMask uint64 = 0x0000
65
66 // Flow types used to divide the available cookie value range
67 // Each type is allocated 256 flow identities which are plenty
68 // for the known use cases.
69
70 // DhcpArpFlowMask constant
71 DhcpArpFlowMask uint64 = 0x0100
72 // PppoeFlowMask constant
73 PppoeFlowMask uint64 = 0x0100
74 // HsiaFlowMask constant
75 HsiaFlowMask uint64 = 0x0200
76 // DsArpFlowMask constant
77 DsArpFlowMask uint64 = 0x0300
78 // IgmpFlowMask constant
79 IgmpFlowMask uint64 = 0x0400
80 // Dhcpv6FlowMask constant
81 Dhcpv6FlowMask uint64 = 0x0800
82
83 // Flow priorities - Higher the value, higher the priority
84
85 // DhcpFlowPriority constant
86 DhcpFlowPriority uint32 = 5000
87 // ArpFlowPriority constant
88 ArpFlowPriority uint32 = 5000
89 // IgmpFlowPriority constant
90 IgmpFlowPriority uint32 = 5000
91 // McFlowPriority constant
92 McFlowPriority uint32 = 5000
93 // PppoeFlowPriority constant
94 PppoeFlowPriority uint32 = 5000
95 // HsiaFlowPriority constant
96 HsiaFlowPriority uint32 = 100
97)
98
99// CookieSetPort to set port
100func CookieSetPort(cookie uint64, port uint32) uint64 {
101 return cookie | (uint64(port) << 32)
102}
103
104// CookieGetPort to get port
105func CookieGetPort(cookie uint64) uint32 {
106 return uint32(cookie >> 32)
107}
108
109// -------------------------------------------------------
110// The flow match and action related definitions follow
111// -------------------------------------------------------
112// The Ethernet types listed below serve our requirement. We may extend
113// the list as we identify more use cases to be supported.
114
115// EtherType type
116type EtherType uint16
117
118const (
119 // EtherTypeAny constant
120 EtherTypeAny EtherType = 0x0000 // Needs assertion
121 // EtherTypeIpv4 constant
122 EtherTypeIpv4 EtherType = 0x0800
123 // EtherTypeIpv6 constant
124 EtherTypeIpv6 EtherType = 0x86DD
125 // EtherTypePppoeDiscovery constant
126 EtherTypePppoeDiscovery EtherType = 0x8863
127 // EtherTypePppoeSession constant
128 EtherTypePppoeSession EtherType = 0x8864
129 // EtherTypeArp constant
130 EtherTypeArp EtherType = 0x0806
131)
132
133// VLAN related definitions
134// VLANs can take a value between 1 and 4095. VLAN 0 is used to set just
135// the PCP bytes. VLAN 4097 is being used to represent "no VLAN"
136// 4096 is being used to represent "any vlan"
137
138// VlanType type
139type VlanType uint16
140
141const (
142 // VlanAny constant
143 VlanAny VlanType = 0x1000
144 // VlanNone constant
145 VlanNone VlanType = 0x1001
146)
147
148func (vlan *VlanType) String() string {
149 return strconv.Itoa(int(*vlan))
150}
151
152// IP Protocol defintions
153// IP protocol 0xff is reserved and we are using the reserved value to
154// represent that match is not needed.
155
156// IPProtocol type
157type IPProtocol uint8
158
159const (
160 // IPProtocolIgnore constant
161 IPProtocolIgnore IPProtocol = 0xff
162 // IPProtocolTCP constant
163 IPProtocolTCP IPProtocol = 0x06
164 // IPProtocolUDP constant
165 IPProtocolUDP IPProtocol = 0x11
166 // IPProtocolIgmp constant
167 IPProtocolIgmp IPProtocol = 0x02
168 // IPProtocolIcmpv6 constant
169 IPProtocolIcmpv6 IPProtocol = 0x3A
170)
171
172// The following structure is included in each flow which further is
173// used to create a flow. The match structure is used to specify the
174// match rules encoded into the flow.
175
176// Match structure
177type Match struct {
178 InPort uint32
179 MatchVlan VlanType
180 SrcMacMatch bool
181 SrcMacAddr net.HardwareAddr
182 SrcMacMask net.HardwareAddr
183 DstMacMatch bool
184 DstMacAddr net.HardwareAddr
185 DstMacMask net.HardwareAddr
186 MatchPbits bool
187 Pbits PbitType
188 L3Protocol EtherType
189 SrcIpv4Match bool
190 SrcIpv4Addr net.IP
191 DstIpv4Match bool
192 DstIpv4Addr net.IP
193 L4Protocol IPProtocol
194 SrcPort uint16
195 DstPort uint16
196 TableMetadata uint64
197}
198
199// Reset to be used when a Match is created. It sets the values to
200// defaults which results is no match rules at all and thus when
201// applied on a port, match all packets. The match rules must be
202// set before use.
203func (m *Match) Reset() {
204 m.MatchVlan = VlanNone
205 m.SrcMacMatch = false
206 m.DstMacMatch = false
207 m.MatchPbits = false
208 m.L3Protocol = EtherTypeAny
209 m.L4Protocol = IPProtocolIgnore
210 m.SrcPort = 0
211 m.DstPort = 0
212 m.TableMetadata = 0
213}
214
215// SetInPort to set in port
216func (m *Match) SetInPort(port uint32) {
217 m.InPort = port
218}
219
220// SetMatchVlan to set match vlan
221func (m *Match) SetMatchVlan(vlan VlanType) {
222 m.MatchVlan = vlan
223}
224
225// SetPppoeDiscoveryMatch to set L3 protocol
226func (m *Match) SetPppoeDiscoveryMatch() {
227 m.L3Protocol = EtherTypePppoeDiscovery
228}
229
230// SetTableMetadata to set table metadata
231func (m *Match) SetTableMetadata(metadata uint64) {
232 m.TableMetadata = metadata
233}
234
235// SetMatchSrcMac to set source mac address
236func (m *Match) SetMatchSrcMac(mac net.HardwareAddr) {
237 m.SrcMacMatch = true
238 m.SrcMacAddr = mac
239}
240
241// SetMatchDstMac to set destination mac address
242func (m *Match) SetMatchDstMac(mac net.HardwareAddr) {
243 m.DstMacMatch = true
244 m.DstMacAddr = mac
245}
246
247// SetMatchPbit to set pbits
248func (m *Match) SetMatchPbit(pbit PbitType) {
249 m.MatchPbits = true
250 m.Pbits = pbit
251}
252
253// SetMatchSrcIpv4 to set source ipv4 address
254func (m *Match) SetMatchSrcIpv4(ip net.IP) {
255 m.SrcIpv4Match = true
256 m.SrcIpv4Addr = ip
257}
258
259// SetMatchDstIpv4 to set destination ipv4 address
260func (m *Match) SetMatchDstIpv4(ip net.IP) {
261 m.DstIpv4Match = true
262 m.DstIpv4Addr = ip
263}
264
265// SetArpMatch to set L3 protocol as Arp
266func (m *Match) SetArpMatch() {
267 m.L3Protocol = EtherTypeArp
268}
269
270// SetICMPv6Match to set L3 and L4 protocol as IPV6 and ICMPv6
271func (m *Match) SetICMPv6Match() {
272 m.L3Protocol = EtherTypeIpv6
273 m.L4Protocol = IPProtocolIcmpv6
274}
275
276// SetUdpv4Match to set L3 and L4 protocol as IPv4 and UDP
277func (m *Match) SetUdpv4Match() {
278 m.L3Protocol = EtherTypeIpv4
279 m.L4Protocol = IPProtocolUDP
280}
281
282// SetIgmpMatch to set L3 and L4 protocol as IPv4 and Igmp
283func (m *Match) SetIgmpMatch() {
284 m.L3Protocol = EtherTypeIpv4
285 m.L4Protocol = IPProtocolIgmp
286}
287
288// SetUdpv6Match to set L3 and L4 protocol as IPv6 and UDP
289func (m *Match) SetUdpv6Match() {
290 m.L3Protocol = EtherTypeIpv6
291 m.L4Protocol = IPProtocolUDP
292}
293
294// SetIpv4Match to set L3 as IPv4
295func (m *Match) SetIpv4Match() {
296 m.L3Protocol = EtherTypeIpv4
297}
298
299// OutputType type
300type OutputType uint8
301
302const (
303 // OutputTypeDrop constant
304 OutputTypeDrop OutputType = 1
305 // OutputTypeToController constant
306 OutputTypeToController OutputType = 2
307 // OutputTypeToNetwork constant
308 OutputTypeToNetwork OutputType = 3
309 // OutputTypeGoToTable constant
310 OutputTypeGoToTable OutputType = 4
311 // OutputTypeToGroup constant
312 OutputTypeToGroup OutputType = 5
313)
314
315const (
316 // FlowAddSuccess constant
317 FlowAddSuccess = 0
318 // FlowAddFailure constant
319 FlowAddFailure = 1
320 // FlowAddPending constant
321 FlowAddPending = 2
322 // FlowDelPending constant
323 FlowDelPending = 3
324 // FlowDelFailure constant
325 FlowDelFailure = 4
326)
327
328// Action structure
329type Action struct {
330 Output OutputType
331 PushVlan []VlanType
332 EtherType layers.EthernetType
333 SetVlan VlanType
334 RemoveVlan int
335 OutPort uint32
336 GoToTableID uint32
337 Metadata uint64
338 MeterID uint32
339 Pcp PbitType
340}
341
342const (
343 // PbitNone constant
344 PbitNone PbitType = 8
345)
346
347// Reset the action structure
348func (a *Action) Reset() {
349 a.Output = OutputTypeDrop
350 a.PushVlan = make([]VlanType, 0)
351 a.SetVlan = VlanNone
352 a.RemoveVlan = 0
353 a.Metadata = 0
354 a.MeterID = 0
355 a.Pcp = PbitNone
356}
357
358// SetReportToController for set action to report to controller
359func (a *Action) SetReportToController() {
360 a.Output = OutputTypeToController
361 a.OutPort = ControllerPort
362}
363
364// SetPushVlan for set action to push to vlan
365func (a *Action) SetPushVlan(vlan VlanType, etherType layers.EthernetType) {
366 a.PushVlan = append(a.PushVlan, vlan)
367 a.EtherType = etherType
368}
369
370// SetSetVlan to set SetVlan
371func (a *Action) SetSetVlan(vlan VlanType) {
372 a.SetVlan = vlan
373}
374
375// SetPopVlan to set remove vlan counter
376func (a *Action) SetPopVlan() {
377 a.RemoveVlan++
378}
379
380// SetMeterID to set meter id
381func (a *Action) SetMeterID(meterID uint32) {
382 a.MeterID = meterID
383}
384
385// SetWriteMetadata to set metadata
386func (a *Action) SetWriteMetadata(metadata uint64) {
387 a.Metadata = metadata
388}
389
390// SetPcp to set pcp
391func (a *Action) SetPcp(pcp PbitType) {
392 a.Pcp = pcp
393}
394
395// GetWriteMetadata returns metadata
396func (a *Action) GetWriteMetadata() uint64 {
397 return a.Metadata
398}
399
400// SetOutPort to set output port
401func (a *Action) SetOutPort(port uint32) {
402 a.Output = OutputTypeToNetwork
403 a.OutPort = port
404}
405
406// SetOutGroup to set output group
407func (a *Action) SetOutGroup(group uint32) {
408 a.Output = OutputTypeToGroup
409 a.OutPort = group
410}
411
412// SetGoToTable to set GoToTableID
413func (a *Action) SetGoToTable(table uint32) {
414 a.Output = OutputTypeGoToTable
415 a.GoToTableID = table
416}
417
418// VoltSubFlow structure
419type VoltSubFlow struct {
420 Cookie uint64
421 CookieMask uint64
422 // OldCookie is used in vgc upgrade when there is cookie generation logic change.
423 OldCookie uint64
424 TableID uint32
425 Priority uint32
426 State uint8
427 ErrorReason string
428 Match
429 Action
430}
431
432// NewVoltSubFlow is constructor for VoltSubFlow
433func NewVoltSubFlow() *VoltSubFlow {
434 var sf VoltSubFlow
435 sf.Match.Reset()
436 sf.Action.Reset()
437 return &sf
438}
439
440// SetTableID to set table id
441func (sf *VoltSubFlow) SetTableID(tableID uint32) {
442 sf.TableID = tableID
443}
444
445// Command type
446type Command uint8
447
448const (
449 // CommandAdd constant
450 CommandAdd Command = 0
451 // CommandDel constant
452 CommandDel Command = 1
453)
454
455// VoltFlow : Definition of a flow
456type VoltFlow struct {
457 Command Command
458 SubFlows map[uint64]*VoltSubFlow
459 ForceAction bool
460 MigrateCookie bool
461 // PortName and PortID to be used for validation of port before flow pushing
462 PortName string
463 PortID uint32
464}
465
466const (
467 // PrevBwInfo indicates the string returned by core for bandwidth consumed before creating scheduler
468 PrevBwInfo string = "prevBW"
469 // PresentBwInfo indicates the string returned by core for bandwidth consumed after creating scheduler
470 PresentBwInfo string = "presentBW"
471)
472
473// BwAvailDetails consists of bw consumtion details at olt
474type BwAvailDetails struct {
475 PrevBw string
476 PresentBw string
477}
478
479// -------------------------------------------------------------------
480// OPENFLOW Implementation of flows
481//
482// The flows constructed using the above structures is translated to
483// the VOLTHA OpenFlow GRPC structures. The code below is used to
484// construct the VOLTHA OF GRPC structures.
485const (
486 // DefaultMeterID constant
487 DefaultMeterID uint32 = 0x1
488 // DefaultBufferID constant
489 DefaultBufferID uint32 = 0xffffffff
490 // DefaultOutPort constant
491 DefaultOutPort uint32 = 0xffffffff
492 // DefaultOutGroup constant
493 DefaultOutGroup uint32 = 0xffffffff
494 // DefaultFlags constant
495 DefaultFlags uint32 = 0x1
496)
497
498// NewInportMatch for inport info
499func NewInportMatch(port uint32) *ofp.OfpOxmField {
500 var entry ofp.OfpOxmField
501 var mf ofp.OfpOxmOfbField
502 entry.OxmClass = ofp.OfpOxmClass_OFPXMC_OPENFLOW_BASIC
503 entry.Field = &ofp.OfpOxmField_OfbField{OfbField: &mf}
504 mf.Type = ofp.OxmOfbFieldTypes_OFPXMT_OFB_IN_PORT
505 mf.HasMask = false
506 mf.Value = &ofp.OfpOxmOfbField_Port{Port: port}
507 return &entry
508}
509
510// NewTableMetadataMatch for table metadata
511func NewTableMetadataMatch(metadata uint64) *ofp.OfpOxmField {
512 var entry ofp.OfpOxmField
513 var mf ofp.OfpOxmOfbField
514 entry.OxmClass = ofp.OfpOxmClass_OFPXMC_OPENFLOW_BASIC
515 entry.Field = &ofp.OfpOxmField_OfbField{OfbField: &mf}
516 mf.Type = ofp.OxmOfbFieldTypes_OFPXMT_OFB_METADATA
517 mf.HasMask = false
518 mf.Value = &ofp.OfpOxmOfbField_TableMetadata{TableMetadata: metadata}
519 return &entry
520}
521
522// NewSrcMacAddrMatch for source mac address info
523func NewSrcMacAddrMatch(addr []byte) *ofp.OfpOxmField {
524 var entry ofp.OfpOxmField
525 var mf ofp.OfpOxmOfbField
526 entry.OxmClass = ofp.OfpOxmClass_OFPXMC_OPENFLOW_BASIC
527 entry.Field = &ofp.OfpOxmField_OfbField{OfbField: &mf}
528 mf.Type = ofp.OxmOfbFieldTypes_OFPXMT_OFB_ETH_SRC
529 mf.HasMask = false
530 mf.Value = &ofp.OfpOxmOfbField_EthSrc{EthSrc: addr}
531 return &entry
532}
533
534// NewDstMacAddrMatch for destination mac address info
535func NewDstMacAddrMatch(addr []byte) *ofp.OfpOxmField {
536 var entry ofp.OfpOxmField
537 var mf ofp.OfpOxmOfbField
538 entry.OxmClass = ofp.OfpOxmClass_OFPXMC_OPENFLOW_BASIC
539 entry.Field = &ofp.OfpOxmField_OfbField{OfbField: &mf}
540 mf.Type = ofp.OxmOfbFieldTypes_OFPXMT_OFB_ETH_DST
541 mf.HasMask = false
542 mf.Value = &ofp.OfpOxmOfbField_EthDst{EthDst: addr}
543 return &entry
544}
545
546// NewVlanMatch for vlan info
547func NewVlanMatch(vlan uint16) *ofp.OfpOxmField {
548 var entry ofp.OfpOxmField
549 var mf ofp.OfpOxmOfbField
550 entry.OxmClass = ofp.OfpOxmClass_OFPXMC_OPENFLOW_BASIC
551 entry.Field = &ofp.OfpOxmField_OfbField{OfbField: &mf}
552 mf.Type = ofp.OxmOfbFieldTypes_OFPXMT_OFB_VLAN_VID
553 mf.HasMask = false
554 mf.Value = &ofp.OfpOxmOfbField_VlanVid{VlanVid: uint32(vlan&0x0fff + 0x1000)}
555 mf.Mask = &ofp.OfpOxmOfbField_VlanVidMask{VlanVidMask: uint32(0x1000)}
556 return &entry
557}
558
559// NewPcpMatch for pcp info
560func NewPcpMatch(pbits PbitType) *ofp.OfpOxmField {
561 var entry ofp.OfpOxmField
562 var mf ofp.OfpOxmOfbField
563 entry.OxmClass = ofp.OfpOxmClass_OFPXMC_OPENFLOW_BASIC
564 entry.Field = &ofp.OfpOxmField_OfbField{OfbField: &mf}
565 mf.Type = ofp.OxmOfbFieldTypes_OFPXMT_OFB_VLAN_PCP
566 mf.HasMask = false
567 mf.Value = &ofp.OfpOxmOfbField_VlanPcp{VlanPcp: uint32(pbits)}
568 return &entry
569}
570
571// NewEthTypeMatch for eth type info
572func NewEthTypeMatch(l3proto uint16) *ofp.OfpOxmField {
573 var entry ofp.OfpOxmField
574 var mf ofp.OfpOxmOfbField
575 entry.OxmClass = ofp.OfpOxmClass_OFPXMC_OPENFLOW_BASIC
576 entry.Field = &ofp.OfpOxmField_OfbField{OfbField: &mf}
577 mf.Type = ofp.OxmOfbFieldTypes_OFPXMT_OFB_ETH_TYPE
578 mf.HasMask = false
579 mf.Value = &ofp.OfpOxmOfbField_EthType{EthType: uint32(l3proto)}
580 return &entry
581}
582
583// ipv4ToUint to convert ipv4 to uint
584func ipv4ToUint(ip net.IP) uint32 {
585 result := uint32(0)
586 addr := ip.To4()
587 if addr == nil {
588 logger.Warnw(ctx, "Invalid Group Addr", log.Fields{"IP": ip})
589 return 0
590 }
591 result = result + uint32(addr[0])<<24
592 result = result + uint32(addr[1])<<16
593 result = result + uint32(addr[2])<<8
594 result = result + uint32(addr[3])
595 return result
596}
597
598// NewIpv4SrcMatch for ipv4 source address
599func NewIpv4SrcMatch(ip net.IP) *ofp.OfpOxmField {
600 var entry ofp.OfpOxmField
601 var mf ofp.OfpOxmOfbField
602 entry.OxmClass = ofp.OfpOxmClass_OFPXMC_OPENFLOW_BASIC
603 entry.Field = &ofp.OfpOxmField_OfbField{OfbField: &mf}
604 mf.Type = ofp.OxmOfbFieldTypes_OFPXMT_OFB_IPV4_SRC
605 mf.HasMask = false
606 mf.Value = &ofp.OfpOxmOfbField_Ipv4Src{Ipv4Src: ipv4ToUint(ip)}
607 return &entry
608}
609
610// NewIpv4DstMatch for ipv4 destination address
611func NewIpv4DstMatch(ip net.IP) *ofp.OfpOxmField {
612 var entry ofp.OfpOxmField
613 var mf ofp.OfpOxmOfbField
614 entry.OxmClass = ofp.OfpOxmClass_OFPXMC_OPENFLOW_BASIC
615 entry.Field = &ofp.OfpOxmField_OfbField{OfbField: &mf}
616 mf.Type = ofp.OxmOfbFieldTypes_OFPXMT_OFB_IPV4_DST
617 mf.HasMask = false
618 mf.Value = &ofp.OfpOxmOfbField_Ipv4Dst{Ipv4Dst: ipv4ToUint(ip)}
619 return &entry
620}
621
622// NewIPProtoMatch for ip proto info
623func NewIPProtoMatch(l4proto uint16) *ofp.OfpOxmField {
624 var entry ofp.OfpOxmField
625 var mf ofp.OfpOxmOfbField
626 entry.OxmClass = ofp.OfpOxmClass_OFPXMC_OPENFLOW_BASIC
627 entry.Field = &ofp.OfpOxmField_OfbField{OfbField: &mf}
628 mf.Type = ofp.OxmOfbFieldTypes_OFPXMT_OFB_IP_PROTO
629 mf.HasMask = false
630 mf.Value = &ofp.OfpOxmOfbField_IpProto{IpProto: uint32(l4proto)}
631 return &entry
632}
633
634// NewUDPSrcMatch for source udp info
635func NewUDPSrcMatch(port uint16) *ofp.OfpOxmField {
636 var entry ofp.OfpOxmField
637 var mf ofp.OfpOxmOfbField
638 entry.OxmClass = ofp.OfpOxmClass_OFPXMC_OPENFLOW_BASIC
639 entry.Field = &ofp.OfpOxmField_OfbField{OfbField: &mf}
640 mf.Type = ofp.OxmOfbFieldTypes_OFPXMT_OFB_UDP_SRC
641 mf.HasMask = false
642 mf.Value = &ofp.OfpOxmOfbField_UdpSrc{UdpSrc: uint32(port)}
643 return &entry
644}
645
646// NewUDPDstMatch for destination udp info
647func NewUDPDstMatch(port uint16) *ofp.OfpOxmField {
648 var entry ofp.OfpOxmField
649 var mf ofp.OfpOxmOfbField
650 entry.OxmClass = ofp.OfpOxmClass_OFPXMC_OPENFLOW_BASIC
651 entry.Field = &ofp.OfpOxmField_OfbField{OfbField: &mf}
652 mf.Type = ofp.OxmOfbFieldTypes_OFPXMT_OFB_UDP_DST
653 mf.HasMask = false
654 mf.Value = &ofp.OfpOxmOfbField_UdpDst{UdpDst: uint32(port)}
655 return &entry
656}
657
658// NewMeterIDInstruction for meter id instructions
659func NewMeterIDInstruction(meterID uint32) *ofp.OfpInstruction {
660 var meter ofp.OfpInstruction
661 meter.Type = uint32(ofp.OfpInstructionType_OFPIT_METER)
662 meter.Data = &ofp.OfpInstruction_Meter{
663 Meter: &ofp.OfpInstructionMeter{
664 MeterId: meterID,
665 },
666 }
667 return &meter
668}
669
670// NewGoToTableInstruction for go to table instructions
671func NewGoToTableInstruction(table uint32) *ofp.OfpInstruction {
672 var gotoTable ofp.OfpInstruction
673 gotoTable.Type = uint32(ofp.OfpInstructionType_OFPIT_GOTO_TABLE)
674 gotoTable.Data = &ofp.OfpInstruction_GotoTable{
675 GotoTable: &ofp.OfpInstructionGotoTable{
676 TableId: table,
677 },
678 }
679 return &gotoTable
680}
681
682// NewPopVlanInstruction for pop vlan instructions
683func NewPopVlanInstruction() *ofp.OfpInstruction {
684 var removeTag ofp.OfpInstruction
685 var actions ofp.OfpInstructionActions
686 removeTag.Type = uint32(ofp.OfpInstructionType_OFPIT_APPLY_ACTIONS)
687 removeTag.Data = &ofp.OfpInstruction_Actions{
688 Actions: &actions,
689 }
690 action := flows.PopVlan()
691 actions.Actions = append(actions.Actions, action)
692 return &removeTag
693}
694
695// NewWriteMetadataInstruction for write metadata instructions
696func NewWriteMetadataInstruction(metadata uint64) *ofp.OfpInstruction {
697 var md ofp.OfpInstruction
698 md.Type = uint32(ofp.OfpInstructionType_OFPIT_WRITE_METADATA)
699 md.Data = &ofp.OfpInstruction_WriteMetadata{WriteMetadata: &ofp.OfpInstructionWriteMetadata{Metadata: metadata}}
700 return &md
701}
702
703// NewPopVlanAction for pop vlan action
704func NewPopVlanAction() *ofp.OfpAction {
705 return flows.PopVlan()
706}
707
708// NewPushVlanInstruction for push vlan instructions
709func NewPushVlanInstruction(vlan uint16, etherType uint32) *ofp.OfpInstruction {
710 var addTag ofp.OfpInstruction
711 var actions ofp.OfpInstructionActions
712 addTag.Type = uint32(ofp.OfpInstructionType_OFPIT_APPLY_ACTIONS)
713 addTag.Data = &ofp.OfpInstruction_Actions{
714 Actions: &actions,
715 }
716 pushAction := flows.PushVlan(etherType)
717 actions.Actions = append(actions.Actions, pushAction)
718 var setField ofp.OfpOxmOfbField
719 setField.Type = ofp.OxmOfbFieldTypes_OFPXMT_OFB_VLAN_VID
720 setField.HasMask = false
721 setField.Value = &ofp.OfpOxmOfbField_VlanVid{
722 VlanVid: uint32(vlan&0x0fff + 0x1000),
723 }
724 setAction := flows.SetField(&setField)
725 actions.Actions = append(actions.Actions, setAction)
726 return &addTag
727}
728
729// NewPushVlanAction for push vlan action
730func NewPushVlanAction(etherType uint32) *ofp.OfpAction {
731 pushAction := flows.PushVlan(etherType)
732 return pushAction
733}
734
735// NewSetVlanAction for set vlan action
736func NewSetVlanAction(vlan uint16) *ofp.OfpAction {
737 var setField ofp.OfpOxmOfbField
738 setField.Type = ofp.OxmOfbFieldTypes_OFPXMT_OFB_VLAN_VID
739 setField.HasMask = false
740 and := (vlan & 0xfff)
741 or := and + 0x1000
742 v := uint32(vlan&0x0fff + 0x1000)
743 logger.Infow(ctx, "Vlan Construction", log.Fields{"Vlan": vlan, "vlan&0x0fff": and, "OR": or, "final": v})
744 setField.Value = &ofp.OfpOxmOfbField_VlanVid{
745 VlanVid: uint32(vlan&0x0fff + 0x1000),
746 }
747 setAction := flows.SetField(&setField)
748 return setAction
749}
750
751// NewSetPcpAction for set pcap action
752func NewSetPcpAction(pbits PbitType) *ofp.OfpAction {
753 var setField ofp.OfpOxmOfbField
754 setField.Type = ofp.OxmOfbFieldTypes_OFPXMT_OFB_VLAN_PCP
755 setField.HasMask = false
756 setField.Value = &ofp.OfpOxmOfbField_VlanPcp{VlanPcp: uint32(pbits)}
757 setAction := flows.SetField(&setField)
758 return setAction
759}
760
761// NewOutputInstruction for output instructions
762func NewOutputInstruction(port uint32) *ofp.OfpInstruction {
763 var outport ofp.OfpInstruction
764 var actions ofp.OfpInstructionActions
765 outport.Type = uint32(ofp.OfpInstructionType_OFPIT_APPLY_ACTIONS)
766 outport.Data = &ofp.OfpInstruction_Actions{
767 Actions: &actions,
768 }
769 action := flows.Output(port, 65535)
770 actions.Actions = append(actions.Actions, action)
771 return &outport
772}
773
774// NewOutputAction for output action
775func NewOutputAction(port uint32) *ofp.OfpAction {
776 return flows.Output(port, 65535)
777}
778
779// NewGroupOutputInstruction for group output instructions
780func NewGroupOutputInstruction(group uint32) *ofp.OfpInstruction {
781 var outgroup ofp.OfpInstruction
782 var actions ofp.OfpInstructionActions
783 outgroup.Type = uint32(ofp.OfpInstructionType_OFPIT_APPLY_ACTIONS)
784 outgroup.Data = &ofp.OfpInstruction_Actions{
785 Actions: &actions,
786 }
787 action := flows.Group(group)
788 actions.Actions = append(actions.Actions, action)
789 return &outgroup
790}
791
792// NewGroupAction for group action
793func NewGroupAction(group uint32) *ofp.OfpAction {
794 return flows.Group(group)
795}
796
797// CreateMatchAndActions to create match list and action
798func CreateMatchAndActions(f *VoltSubFlow) ([]*ofp.OfpOxmField, []*ofp.OfpInstruction) {
799 logger.Debug(ctx, "Create Match and Action called")
800
801 // Return values declared here
802 var matchList []*ofp.OfpOxmField
803 var instructions []*ofp.OfpInstruction
804
805 // Construct the match rules
806 // Add match in port
807 if f.Match.InPort != 0 {
808 entry := NewInportMatch(uint32(f.Match.InPort))
809 matchList = append(matchList, entry)
810 }
811
812 // Add table metadata match
813 if f.Match.TableMetadata != 0 {
814 entry := NewTableMetadataMatch(uint64(f.Match.TableMetadata))
815 matchList = append(matchList, entry)
816 }
817
818 // Add Src MAC address match
819 if f.SrcMacMatch {
820 entry := NewSrcMacAddrMatch(f.SrcMacAddr)
821 matchList = append(matchList, entry)
822 }
823
824 // Add Src MAC address match
825 if f.DstMacMatch {
826 entry := NewDstMacAddrMatch(f.DstMacAddr)
827 matchList = append(matchList, entry)
828 }
829
830 // Add VLAN tag match
831 if f.MatchVlan != VlanNone {
832 entry := NewVlanMatch(uint16(f.MatchVlan))
833 matchList = append(matchList, entry)
834 }
835
836 if f.MatchPbits {
837 entry := NewPcpMatch(f.Pbits)
838 matchList = append(matchList, entry)
839 }
840
841 // Add EtherType match
842 if f.L3Protocol != EtherTypeAny {
843 entry := NewEthTypeMatch(uint16(f.L3Protocol))
844 matchList = append(matchList, entry)
845 }
846
847 // Add the Src IPv4 addr match
848 if f.SrcIpv4Match {
849 entry := NewIpv4SrcMatch(f.SrcIpv4Addr)
850 matchList = append(matchList, entry)
851 }
852
853 // Add the Dst IPv4 addr match
854 if f.DstIpv4Match {
855 entry := NewIpv4DstMatch(f.DstIpv4Addr)
856 matchList = append(matchList, entry)
857 }
858
859 // Add IP protocol match
860 if f.L4Protocol != IPProtocolIgnore {
861 entry := NewIPProtoMatch(uint16(f.L4Protocol))
862 matchList = append(matchList, entry)
863 }
864
865 // Add UDP Source port match
866 if f.SrcPort != 0 {
867 entry := NewUDPSrcMatch(uint16(f.SrcPort))
868 matchList = append(matchList, entry)
869 }
870
871 // Add UDP Dest port match
872 if f.DstPort != 0 {
873 entry := NewUDPDstMatch(uint16(f.DstPort))
874 matchList = append(matchList, entry)
875 }
876
877 // Construct the instructions
878 // Add a GOTO table action
879 if f.Output == OutputTypeGoToTable {
880 instruction := NewGoToTableInstruction(f.GoToTableID)
881 instructions = append(instructions, instruction)
882 }
883
884 // Add the meter instruction
885 if f.MeterID != 0 {
886 instruction := NewMeterIDInstruction(f.MeterID)
887 instructions = append(instructions, instruction)
888 }
889
890 // Add the metadata instruction
891 if f.Metadata != 0 {
892 instruction := NewWriteMetadataInstruction(f.Metadata)
893 instructions = append(instructions, instruction)
894 }
895
896 // The below are all apply actions. All of these could be combined into
897 // a single instruction.
898 {
899 var instruction ofp.OfpInstruction
900 var actions ofp.OfpInstructionActions
901 instruction.Type = uint32(ofp.OfpInstructionType_OFPIT_APPLY_ACTIONS)
902 instruction.Data = &ofp.OfpInstruction_Actions{
903 Actions: &actions,
904 }
905
906 // Apply action of popping the VLAN
907 if f.RemoveVlan != 0 {
908 for i := 0; i < f.RemoveVlan; i++ {
909 action := NewPopVlanAction()
910 actions.Actions = append(actions.Actions, action)
911 }
912 }
913
914 if f.SetVlan != VlanNone {
915 action := NewSetVlanAction(uint16(f.SetVlan))
916 actions.Actions = append(actions.Actions, action)
917 }
918
919 if f.Pcp != PbitNone {
920 action := NewSetPcpAction(f.Pcp)
921 actions.Actions = append(actions.Actions, action)
922 }
923
924 // Add the VLAN PUSH
925 if len(f.PushVlan) != 0 {
926 action := NewPushVlanAction(uint32(f.EtherType))
927 actions.Actions = append(actions.Actions, action)
928 for _, vlan := range f.PushVlan {
929 action = NewSetVlanAction(uint16(vlan))
930 actions.Actions = append(actions.Actions, action)
931 }
932 }
933
934 if f.Action.Output == OutputTypeToController {
935 action := NewOutputAction(0xfffffffd)
936 actions.Actions = append(actions.Actions, action)
937 } else if f.Action.Output == OutputTypeToNetwork {
938 action := NewOutputAction(f.OutPort)
939 actions.Actions = append(actions.Actions, action)
940 } else if f.Action.Output == OutputTypeToGroup {
941 action := NewGroupAction(f.OutPort)
942 actions.Actions = append(actions.Actions, action)
943 }
944 instructions = append(instructions, &instruction)
945 }
946
947 return matchList, instructions
948}
949
950// CreateFlow to create flow
951func CreateFlow(device string, command ofp.OfpFlowModCommand, matches []*ofp.OfpOxmField,
952 instructions []*ofp.OfpInstruction, sf *VoltSubFlow) *ofp.FlowTableUpdate {
953 flowUpdate := ofp.FlowTableUpdate{
954 Id: device,
955 FlowMod: &ofp.OfpFlowMod{
956 Cookie: sf.Cookie,
957 CookieMask: sf.CookieMask,
958 TableId: sf.TableID,
959 Command: command,
960 IdleTimeout: uint32(0),
961 HardTimeout: uint32(0),
962 Priority: sf.Priority,
963 BufferId: DefaultBufferID,
964 OutPort: DefaultOutPort,
965 OutGroup: DefaultOutGroup,
966 Flags: DefaultFlags,
967 Match: &ofp.OfpMatch{
968 Type: ofp.OfpMatchType_OFPMT_OXM,
969 OxmFields: matches,
970 },
971
972 Instructions: instructions,
973 },
974 }
975 return &flowUpdate
976}
977
978// Processing logic for the VOLT flows. The VOLT flows are different from
979// the normal openflows. Each VOLT flow may break into multiple flows.
980// The order of processing:
981// 1. If the flow has to match more than one VLAN tag, it is broken into
982// more than one flow.
983// 2. When more than one flow is creatd, the higher layer processing is
984// broken into the second flow. The first flow includes only the
985// the processing of first VLAN tag.
986// 3. The a sinle flow is created, the first flow has all the match criteria
987// and action.
988
989// ProcessVoltFlow to process volt flow
990func ProcessVoltFlow(device string, operation Command, subFlow map[uint64]*VoltSubFlow) []*ofp.FlowTableUpdate {
991 var flows []*ofp.FlowTableUpdate
992 var command ofp.OfpFlowModCommand
993 if operation == CommandAdd {
994 command = ofp.OfpFlowModCommand_OFPFC_ADD
995 } else {
996 command = ofp.OfpFlowModCommand_OFPFC_DELETE_STRICT
997 }
998 for _, sf := range subFlow {
999 logger.Debugw(ctx, "Flow Construction for", log.Fields{"Flow": sf})
1000 match, instruction := CreateMatchAndActions(sf)
1001 flow := CreateFlow(device, command, match, instruction, sf)
1002 logger.Debugw(ctx, "Flow Constructed", log.Fields{"Flow": flow})
1003 flows = append(flows, flow)
1004 }
1005 return flows
1006}
1007
1008func init() {
1009 // Setup this package so that it's log level can be modified at run time
1010 var err error
Tinoj Joseph1d108322022-07-13 10:07:39 +05301011 logger, err = log.AddPackageWithDefaultParam()
Naveen Sampath04696f72022-06-13 15:19:14 +05301012 if err != nil {
1013 panic(err)
1014 }
1015}