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