blob: 2cc84ac3b640a6fa42c590f72729b21f4f6dac87 [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"
26 "github.com/opencord/voltha-lib-go/v7/pkg/log"
27 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
43
44var 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 {
179 InPort uint32
180 MatchVlan VlanType
181 SrcMacMatch bool
182 SrcMacAddr net.HardwareAddr
183 SrcMacMask net.HardwareAddr
184 DstMacMatch bool
185 DstMacAddr net.HardwareAddr
186 DstMacMask net.HardwareAddr
187 MatchPbits bool
188 Pbits PbitType
189 L3Protocol EtherType
190 SrcIpv4Match bool
191 SrcIpv4Addr net.IP
192 DstIpv4Match bool
193 DstIpv4Addr net.IP
194 L4Protocol IPProtocol
195 SrcPort uint16
196 DstPort uint16
197 TableMetadata uint64
198}
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 {
331 Output OutputType
332 PushVlan []VlanType
333 EtherType layers.EthernetType
334 SetVlan VlanType
335 RemoveVlan int
336 OutPort uint32
337 GoToTableID uint32
338 Metadata uint64
339 MeterID uint32
340 Pcp PbitType
341}
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 {
421 Cookie uint64
422 CookieMask uint64
423 // OldCookie is used in vgc upgrade when there is cookie generation logic change.
424 OldCookie uint64
425 TableID uint32
426 Priority uint32
427 State uint8
428 ErrorReason string
429 Match
430 Action
431}
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 {
458 Command Command
459 SubFlows map[uint64]*VoltSubFlow
460 ForceAction bool
461 MigrateCookie bool
462 // PortName and PortID to be used for validation of port before flow pushing
463 PortName string
464 PortID uint32
465}
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
1012 logger, err = log.RegisterPackage(log.JSON, log.ErrorLevel, log.Fields{})
1013 if err != nil {
1014 panic(err)
1015 }
1016}