blob: 8a6333fe02944d1dcb50f91de56132c04fc498e1 [file] [log] [blame]
Scott Baker456b8932019-10-24 10:36:39 -07001/*
Joey Armstrong9cdee9f2024-01-03 04:56:14 -05002 * Copyright 2018-2024 Open Networking Foundation (ONF) and the ONF Contributors
Scott Baker456b8932019-10-24 10:36:39 -07003 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
Akash Reddy Kankanala05aff182025-05-06 12:57:32 +053016//nolint:staticcheck
Scott Baker456b8932019-10-24 10:36:39 -070017package flows
18
19import (
20 "bytes"
Neha Sharma94f16a92020-06-26 04:17:55 +000021 "context"
Scott Baker456b8932019-10-24 10:36:39 -070022 "crypto/md5"
Kent Hagermanf9cbe692020-05-05 17:50:26 -040023 "encoding/binary"
Scott Baker456b8932019-10-24 10:36:39 -070024 "fmt"
Kent Hagermanf9cbe692020-05-05 17:50:26 -040025 "hash"
26 "sort"
khenaidoo26721882021-08-11 17:42:52 -040027 "sync"
Kent Hagermanf9cbe692020-05-05 17:50:26 -040028
Scott Baker456b8932019-10-24 10:36:39 -070029 "github.com/cevaris/ordered_map"
khenaidoo26721882021-08-11 17:42:52 -040030 "github.com/golang/protobuf/proto"
31 "github.com/opencord/voltha-lib-go/v7/pkg/log"
32 ofp "github.com/opencord/voltha-protos/v5/go/openflow_13"
Scott Baker456b8932019-10-24 10:36:39 -070033)
34
35var (
36 // Instructions shortcut
37 APPLY_ACTIONS = ofp.OfpInstructionType_OFPIT_APPLY_ACTIONS
38 WRITE_METADATA = ofp.OfpInstructionType_OFPIT_WRITE_METADATA
39 METER_ACTION = ofp.OfpInstructionType_OFPIT_METER
40
41 //OFPAT_* shortcuts
42 OUTPUT = ofp.OfpActionType_OFPAT_OUTPUT
43 COPY_TTL_OUT = ofp.OfpActionType_OFPAT_COPY_TTL_OUT
44 COPY_TTL_IN = ofp.OfpActionType_OFPAT_COPY_TTL_IN
45 SET_MPLS_TTL = ofp.OfpActionType_OFPAT_SET_MPLS_TTL
46 DEC_MPLS_TTL = ofp.OfpActionType_OFPAT_DEC_MPLS_TTL
47 PUSH_VLAN = ofp.OfpActionType_OFPAT_PUSH_VLAN
48 POP_VLAN = ofp.OfpActionType_OFPAT_POP_VLAN
49 PUSH_MPLS = ofp.OfpActionType_OFPAT_PUSH_MPLS
50 POP_MPLS = ofp.OfpActionType_OFPAT_POP_MPLS
51 SET_QUEUE = ofp.OfpActionType_OFPAT_SET_QUEUE
52 GROUP = ofp.OfpActionType_OFPAT_GROUP
53 SET_NW_TTL = ofp.OfpActionType_OFPAT_SET_NW_TTL
54 NW_TTL = ofp.OfpActionType_OFPAT_DEC_NW_TTL
55 SET_FIELD = ofp.OfpActionType_OFPAT_SET_FIELD
56 PUSH_PBB = ofp.OfpActionType_OFPAT_PUSH_PBB
57 POP_PBB = ofp.OfpActionType_OFPAT_POP_PBB
58 EXPERIMENTER = ofp.OfpActionType_OFPAT_EXPERIMENTER
59
60 //OFPXMT_OFB_* shortcuts (incomplete)
61 IN_PORT = ofp.OxmOfbFieldTypes_OFPXMT_OFB_IN_PORT
62 IN_PHY_PORT = ofp.OxmOfbFieldTypes_OFPXMT_OFB_IN_PHY_PORT
63 METADATA = ofp.OxmOfbFieldTypes_OFPXMT_OFB_METADATA
64 ETH_DST = ofp.OxmOfbFieldTypes_OFPXMT_OFB_ETH_DST
65 ETH_SRC = ofp.OxmOfbFieldTypes_OFPXMT_OFB_ETH_SRC
66 ETH_TYPE = ofp.OxmOfbFieldTypes_OFPXMT_OFB_ETH_TYPE
67 VLAN_VID = ofp.OxmOfbFieldTypes_OFPXMT_OFB_VLAN_VID
68 VLAN_PCP = ofp.OxmOfbFieldTypes_OFPXMT_OFB_VLAN_PCP
69 IP_DSCP = ofp.OxmOfbFieldTypes_OFPXMT_OFB_IP_DSCP
70 IP_ECN = ofp.OxmOfbFieldTypes_OFPXMT_OFB_IP_ECN
71 IP_PROTO = ofp.OxmOfbFieldTypes_OFPXMT_OFB_IP_PROTO
72 IPV4_SRC = ofp.OxmOfbFieldTypes_OFPXMT_OFB_IPV4_SRC
73 IPV4_DST = ofp.OxmOfbFieldTypes_OFPXMT_OFB_IPV4_DST
74 TCP_SRC = ofp.OxmOfbFieldTypes_OFPXMT_OFB_TCP_SRC
75 TCP_DST = ofp.OxmOfbFieldTypes_OFPXMT_OFB_TCP_DST
76 UDP_SRC = ofp.OxmOfbFieldTypes_OFPXMT_OFB_UDP_SRC
77 UDP_DST = ofp.OxmOfbFieldTypes_OFPXMT_OFB_UDP_DST
78 SCTP_SRC = ofp.OxmOfbFieldTypes_OFPXMT_OFB_SCTP_SRC
79 SCTP_DST = ofp.OxmOfbFieldTypes_OFPXMT_OFB_SCTP_DST
80 ICMPV4_TYPE = ofp.OxmOfbFieldTypes_OFPXMT_OFB_ICMPV4_TYPE
81 ICMPV4_CODE = ofp.OxmOfbFieldTypes_OFPXMT_OFB_ICMPV4_CODE
82 ARP_OP = ofp.OxmOfbFieldTypes_OFPXMT_OFB_ARP_OP
83 ARP_SPA = ofp.OxmOfbFieldTypes_OFPXMT_OFB_ARP_SPA
84 ARP_TPA = ofp.OxmOfbFieldTypes_OFPXMT_OFB_ARP_TPA
85 ARP_SHA = ofp.OxmOfbFieldTypes_OFPXMT_OFB_ARP_SHA
86 ARP_THA = ofp.OxmOfbFieldTypes_OFPXMT_OFB_ARP_THA
87 IPV6_SRC = ofp.OxmOfbFieldTypes_OFPXMT_OFB_IPV6_SRC
88 IPV6_DST = ofp.OxmOfbFieldTypes_OFPXMT_OFB_IPV6_DST
89 IPV6_FLABEL = ofp.OxmOfbFieldTypes_OFPXMT_OFB_IPV6_FLABEL
90 ICMPV6_TYPE = ofp.OxmOfbFieldTypes_OFPXMT_OFB_ICMPV6_TYPE
91 ICMPV6_CODE = ofp.OxmOfbFieldTypes_OFPXMT_OFB_ICMPV6_CODE
92 IPV6_ND_TARGET = ofp.OxmOfbFieldTypes_OFPXMT_OFB_IPV6_ND_TARGET
93 OFB_IPV6_ND_SLL = ofp.OxmOfbFieldTypes_OFPXMT_OFB_IPV6_ND_SLL
94 IPV6_ND_TLL = ofp.OxmOfbFieldTypes_OFPXMT_OFB_IPV6_ND_TLL
95 MPLS_LABEL = ofp.OxmOfbFieldTypes_OFPXMT_OFB_MPLS_LABEL
96 MPLS_TC = ofp.OxmOfbFieldTypes_OFPXMT_OFB_MPLS_TC
97 MPLS_BOS = ofp.OxmOfbFieldTypes_OFPXMT_OFB_MPLS_BOS
98 PBB_ISID = ofp.OxmOfbFieldTypes_OFPXMT_OFB_PBB_ISID
99 TUNNEL_ID = ofp.OxmOfbFieldTypes_OFPXMT_OFB_TUNNEL_ID
100 IPV6_EXTHDR = ofp.OxmOfbFieldTypes_OFPXMT_OFB_IPV6_EXTHDR
101)
102
103//ofp_action_* shortcuts
104
105func Output(port uint32, maxLen ...ofp.OfpControllerMaxLen) *ofp.OfpAction {
106 maxLength := ofp.OfpControllerMaxLen_OFPCML_MAX
107 if len(maxLen) > 0 {
108 maxLength = maxLen[0]
109 }
110 return &ofp.OfpAction{Type: OUTPUT, Action: &ofp.OfpAction_Output{Output: &ofp.OfpActionOutput{Port: port, MaxLen: uint32(maxLength)}}}
111}
112
113func MplsTtl(ttl uint32) *ofp.OfpAction {
114 return &ofp.OfpAction{Type: SET_MPLS_TTL, Action: &ofp.OfpAction_MplsTtl{MplsTtl: &ofp.OfpActionMplsTtl{MplsTtl: ttl}}}
115}
116
117func PushVlan(ethType uint32) *ofp.OfpAction {
118 return &ofp.OfpAction{Type: PUSH_VLAN, Action: &ofp.OfpAction_Push{Push: &ofp.OfpActionPush{Ethertype: ethType}}}
119}
120
121func PopVlan() *ofp.OfpAction {
122 return &ofp.OfpAction{Type: POP_VLAN}
123}
124
125func PopMpls(ethType uint32) *ofp.OfpAction {
126 return &ofp.OfpAction{Type: POP_MPLS, Action: &ofp.OfpAction_PopMpls{PopMpls: &ofp.OfpActionPopMpls{Ethertype: ethType}}}
127}
128
129func Group(groupId uint32) *ofp.OfpAction {
130 return &ofp.OfpAction{Type: GROUP, Action: &ofp.OfpAction_Group{Group: &ofp.OfpActionGroup{GroupId: groupId}}}
131}
132
133func NwTtl(nwTtl uint32) *ofp.OfpAction {
134 return &ofp.OfpAction{Type: NW_TTL, Action: &ofp.OfpAction_NwTtl{NwTtl: &ofp.OfpActionNwTtl{NwTtl: nwTtl}}}
135}
136
137func SetField(field *ofp.OfpOxmOfbField) *ofp.OfpAction {
138 actionSetField := &ofp.OfpOxmField{OxmClass: ofp.OfpOxmClass_OFPXMC_OPENFLOW_BASIC, Field: &ofp.OfpOxmField_OfbField{OfbField: field}}
139 return &ofp.OfpAction{Type: SET_FIELD, Action: &ofp.OfpAction_SetField{SetField: &ofp.OfpActionSetField{Field: actionSetField}}}
140}
141
142func Experimenter(experimenter uint32, data []byte) *ofp.OfpAction {
143 return &ofp.OfpAction{Type: EXPERIMENTER, Action: &ofp.OfpAction_Experimenter{Experimenter: &ofp.OfpActionExperimenter{Experimenter: experimenter, Data: data}}}
144}
145
146//ofb_field generators (incomplete set)
147
148func InPort(inPort uint32) *ofp.OfpOxmOfbField {
149 return &ofp.OfpOxmOfbField{Type: IN_PORT, Value: &ofp.OfpOxmOfbField_Port{Port: inPort}}
150}
151
152func InPhyPort(inPhyPort uint32) *ofp.OfpOxmOfbField {
153 return &ofp.OfpOxmOfbField{Type: IN_PHY_PORT, Value: &ofp.OfpOxmOfbField_Port{Port: inPhyPort}}
154}
155
156func Metadata_ofp(tableMetadata uint64) *ofp.OfpOxmOfbField {
157 return &ofp.OfpOxmOfbField{Type: METADATA, Value: &ofp.OfpOxmOfbField_TableMetadata{TableMetadata: tableMetadata}}
158}
159
160// should Metadata_ofp used here ?????
161func EthDst(ethDst uint64) *ofp.OfpOxmOfbField {
162 return &ofp.OfpOxmOfbField{Type: ETH_DST, Value: &ofp.OfpOxmOfbField_TableMetadata{TableMetadata: ethDst}}
163}
164
165// should Metadata_ofp used here ?????
166func EthSrc(ethSrc uint64) *ofp.OfpOxmOfbField {
167 return &ofp.OfpOxmOfbField{Type: ETH_SRC, Value: &ofp.OfpOxmOfbField_TableMetadata{TableMetadata: ethSrc}}
168}
169
170func EthType(ethType uint32) *ofp.OfpOxmOfbField {
171 return &ofp.OfpOxmOfbField{Type: ETH_TYPE, Value: &ofp.OfpOxmOfbField_EthType{EthType: ethType}}
172}
173
174func VlanVid(vlanVid uint32) *ofp.OfpOxmOfbField {
175 return &ofp.OfpOxmOfbField{Type: VLAN_VID, Value: &ofp.OfpOxmOfbField_VlanVid{VlanVid: vlanVid}}
176}
177
178func VlanPcp(vlanPcp uint32) *ofp.OfpOxmOfbField {
179 return &ofp.OfpOxmOfbField{Type: VLAN_PCP, Value: &ofp.OfpOxmOfbField_VlanPcp{VlanPcp: vlanPcp}}
180}
181
182func IpDscp(ipDscp uint32) *ofp.OfpOxmOfbField {
183 return &ofp.OfpOxmOfbField{Type: IP_DSCP, Value: &ofp.OfpOxmOfbField_IpDscp{IpDscp: ipDscp}}
184}
185
186func IpEcn(ipEcn uint32) *ofp.OfpOxmOfbField {
187 return &ofp.OfpOxmOfbField{Type: IP_ECN, Value: &ofp.OfpOxmOfbField_IpEcn{IpEcn: ipEcn}}
188}
189
190func IpProto(ipProto uint32) *ofp.OfpOxmOfbField {
191 return &ofp.OfpOxmOfbField{Type: IP_PROTO, Value: &ofp.OfpOxmOfbField_IpProto{IpProto: ipProto}}
192}
193
194func Ipv4Src(ipv4Src uint32) *ofp.OfpOxmOfbField {
195 return &ofp.OfpOxmOfbField{Type: IPV4_SRC, Value: &ofp.OfpOxmOfbField_Ipv4Src{Ipv4Src: ipv4Src}}
196}
197
198func Ipv4Dst(ipv4Dst uint32) *ofp.OfpOxmOfbField {
199 return &ofp.OfpOxmOfbField{Type: IPV4_DST, Value: &ofp.OfpOxmOfbField_Ipv4Dst{Ipv4Dst: ipv4Dst}}
200}
201
202func TcpSrc(tcpSrc uint32) *ofp.OfpOxmOfbField {
203 return &ofp.OfpOxmOfbField{Type: TCP_SRC, Value: &ofp.OfpOxmOfbField_TcpSrc{TcpSrc: tcpSrc}}
204}
205
206func TcpDst(tcpDst uint32) *ofp.OfpOxmOfbField {
207 return &ofp.OfpOxmOfbField{Type: TCP_DST, Value: &ofp.OfpOxmOfbField_TcpDst{TcpDst: tcpDst}}
208}
209
210func UdpSrc(udpSrc uint32) *ofp.OfpOxmOfbField {
211 return &ofp.OfpOxmOfbField{Type: UDP_SRC, Value: &ofp.OfpOxmOfbField_UdpSrc{UdpSrc: udpSrc}}
212}
213
214func UdpDst(udpDst uint32) *ofp.OfpOxmOfbField {
215 return &ofp.OfpOxmOfbField{Type: UDP_DST, Value: &ofp.OfpOxmOfbField_UdpDst{UdpDst: udpDst}}
216}
217
218func SctpSrc(sctpSrc uint32) *ofp.OfpOxmOfbField {
219 return &ofp.OfpOxmOfbField{Type: SCTP_SRC, Value: &ofp.OfpOxmOfbField_SctpSrc{SctpSrc: sctpSrc}}
220}
221
222func SctpDst(sctpDst uint32) *ofp.OfpOxmOfbField {
223 return &ofp.OfpOxmOfbField{Type: SCTP_DST, Value: &ofp.OfpOxmOfbField_SctpDst{SctpDst: sctpDst}}
224}
225
226func Icmpv4Type(icmpv4Type uint32) *ofp.OfpOxmOfbField {
227 return &ofp.OfpOxmOfbField{Type: ICMPV4_TYPE, Value: &ofp.OfpOxmOfbField_Icmpv4Type{Icmpv4Type: icmpv4Type}}
228}
229
230func Icmpv4Code(icmpv4Code uint32) *ofp.OfpOxmOfbField {
231 return &ofp.OfpOxmOfbField{Type: ICMPV4_CODE, Value: &ofp.OfpOxmOfbField_Icmpv4Code{Icmpv4Code: icmpv4Code}}
232}
233
234func ArpOp(arpOp uint32) *ofp.OfpOxmOfbField {
235 return &ofp.OfpOxmOfbField{Type: ARP_OP, Value: &ofp.OfpOxmOfbField_ArpOp{ArpOp: arpOp}}
236}
237
238func ArpSpa(arpSpa uint32) *ofp.OfpOxmOfbField {
239 return &ofp.OfpOxmOfbField{Type: ARP_SPA, Value: &ofp.OfpOxmOfbField_ArpSpa{ArpSpa: arpSpa}}
240}
241
242func ArpTpa(arpTpa uint32) *ofp.OfpOxmOfbField {
243 return &ofp.OfpOxmOfbField{Type: ARP_TPA, Value: &ofp.OfpOxmOfbField_ArpTpa{ArpTpa: arpTpa}}
244}
245
246func ArpSha(arpSha []byte) *ofp.OfpOxmOfbField {
247 return &ofp.OfpOxmOfbField{Type: ARP_SHA, Value: &ofp.OfpOxmOfbField_ArpSha{ArpSha: arpSha}}
248}
249
250func ArpTha(arpTha []byte) *ofp.OfpOxmOfbField {
251 return &ofp.OfpOxmOfbField{Type: ARP_THA, Value: &ofp.OfpOxmOfbField_ArpTha{ArpTha: arpTha}}
252}
253
254func Ipv6Src(ipv6Src []byte) *ofp.OfpOxmOfbField {
255 return &ofp.OfpOxmOfbField{Type: IPV6_SRC, Value: &ofp.OfpOxmOfbField_Ipv6Src{Ipv6Src: ipv6Src}}
256}
257
258func Ipv6Dst(ipv6Dst []byte) *ofp.OfpOxmOfbField {
259 return &ofp.OfpOxmOfbField{Type: IPV6_DST, Value: &ofp.OfpOxmOfbField_Ipv6Dst{Ipv6Dst: ipv6Dst}}
260}
261
262func Ipv6Flabel(ipv6Flabel uint32) *ofp.OfpOxmOfbField {
263 return &ofp.OfpOxmOfbField{Type: IPV6_FLABEL, Value: &ofp.OfpOxmOfbField_Ipv6Flabel{Ipv6Flabel: ipv6Flabel}}
264}
265
266func Icmpv6Type(icmpv6Type uint32) *ofp.OfpOxmOfbField {
267 return &ofp.OfpOxmOfbField{Type: ICMPV6_TYPE, Value: &ofp.OfpOxmOfbField_Icmpv6Type{Icmpv6Type: icmpv6Type}}
268}
269
270func Icmpv6Code(icmpv6Code uint32) *ofp.OfpOxmOfbField {
271 return &ofp.OfpOxmOfbField{Type: ICMPV6_CODE, Value: &ofp.OfpOxmOfbField_Icmpv6Code{Icmpv6Code: icmpv6Code}}
272}
273
274func Ipv6NdTarget(ipv6NdTarget []byte) *ofp.OfpOxmOfbField {
275 return &ofp.OfpOxmOfbField{Type: IPV6_ND_TARGET, Value: &ofp.OfpOxmOfbField_Ipv6NdTarget{Ipv6NdTarget: ipv6NdTarget}}
276}
277
278func OfbIpv6NdSll(ofbIpv6NdSll []byte) *ofp.OfpOxmOfbField {
279 return &ofp.OfpOxmOfbField{Type: OFB_IPV6_ND_SLL, Value: &ofp.OfpOxmOfbField_Ipv6NdSsl{Ipv6NdSsl: ofbIpv6NdSll}}
280}
281
282func Ipv6NdTll(ipv6NdTll []byte) *ofp.OfpOxmOfbField {
283 return &ofp.OfpOxmOfbField{Type: IPV6_ND_TLL, Value: &ofp.OfpOxmOfbField_Ipv6NdTll{Ipv6NdTll: ipv6NdTll}}
284}
285
286func MplsLabel(mplsLabel uint32) *ofp.OfpOxmOfbField {
287 return &ofp.OfpOxmOfbField{Type: MPLS_LABEL, Value: &ofp.OfpOxmOfbField_MplsLabel{MplsLabel: mplsLabel}}
288}
289
290func MplsTc(mplsTc uint32) *ofp.OfpOxmOfbField {
291 return &ofp.OfpOxmOfbField{Type: MPLS_TC, Value: &ofp.OfpOxmOfbField_MplsTc{MplsTc: mplsTc}}
292}
293
294func MplsBos(mplsBos uint32) *ofp.OfpOxmOfbField {
295 return &ofp.OfpOxmOfbField{Type: MPLS_BOS, Value: &ofp.OfpOxmOfbField_MplsBos{MplsBos: mplsBos}}
296}
297
298func PbbIsid(pbbIsid uint32) *ofp.OfpOxmOfbField {
299 return &ofp.OfpOxmOfbField{Type: PBB_ISID, Value: &ofp.OfpOxmOfbField_PbbIsid{PbbIsid: pbbIsid}}
300}
301
302func TunnelId(tunnelId uint64) *ofp.OfpOxmOfbField {
303 return &ofp.OfpOxmOfbField{Type: TUNNEL_ID, Value: &ofp.OfpOxmOfbField_TunnelId{TunnelId: tunnelId}}
304}
305
306func Ipv6Exthdr(ipv6Exthdr uint32) *ofp.OfpOxmOfbField {
307 return &ofp.OfpOxmOfbField{Type: IPV6_EXTHDR, Value: &ofp.OfpOxmOfbField_Ipv6Exthdr{Ipv6Exthdr: ipv6Exthdr}}
308}
309
310//frequently used extractors
311
312func excludeAction(action *ofp.OfpAction, exclude ...ofp.OfpActionType) bool {
313 for _, actionToExclude := range exclude {
314 if action.Type == actionToExclude {
315 return true
316 }
317 }
318 return false
319}
320
321func GetActions(flow *ofp.OfpFlowStats, exclude ...ofp.OfpActionType) []*ofp.OfpAction {
322 if flow == nil {
323 return nil
324 }
325 for _, instruction := range flow.Instructions {
326 if instruction.Type == uint32(ofp.OfpInstructionType_OFPIT_APPLY_ACTIONS) {
327 instActions := instruction.GetActions()
328 if instActions == nil {
329 return nil
330 }
331 if len(exclude) == 0 {
332 return instActions.Actions
333 } else {
334 filteredAction := make([]*ofp.OfpAction, 0)
335 for _, action := range instActions.Actions {
336 if !excludeAction(action, exclude...) {
337 filteredAction = append(filteredAction, action)
338 }
339 }
340 return filteredAction
341 }
342 }
343 }
344 return nil
345}
346
347func UpdateOutputPortByActionType(flow *ofp.OfpFlowStats, actionType uint32, toPort uint32) *ofp.OfpFlowStats {
348 if flow == nil {
349 return nil
350 }
Akash Reddy Kankanala05aff182025-05-06 12:57:32 +0530351 flowData, err := proto.Marshal(flow)
352 if err != nil {
353 return nil // Handle error appropriately
354 }
355 nFlow := &ofp.OfpFlowStats{}
356 if err := proto.Unmarshal(flowData, nFlow); err != nil {
357 return nil // Handle error appropriately
358 }
Scott Baker456b8932019-10-24 10:36:39 -0700359 nFlow.Instructions = nil
360 nInsts := make([]*ofp.OfpInstruction, 0)
361 for _, instruction := range flow.Instructions {
362 if instruction.Type == actionType {
363 instActions := instruction.GetActions()
364 if instActions == nil {
365 return nil
366 }
367 nActions := make([]*ofp.OfpAction, 0)
368 for _, action := range instActions.Actions {
369 if action.GetOutput() != nil {
370 nActions = append(nActions, Output(toPort))
371 } else {
372 nActions = append(nActions, action)
373 }
374 }
375 instructionAction := ofp.OfpInstruction_Actions{Actions: &ofp.OfpInstructionActions{Actions: nActions}}
376 nInsts = append(nInsts, &ofp.OfpInstruction{Type: uint32(APPLY_ACTIONS), Data: &instructionAction})
377 } else {
378 nInsts = append(nInsts, instruction)
379 }
380 }
381 nFlow.Instructions = nInsts
382 return nFlow
383}
384
385func excludeOxmOfbField(field *ofp.OfpOxmOfbField, exclude ...ofp.OxmOfbFieldTypes) bool {
386 for _, fieldToExclude := range exclude {
387 if field.Type == fieldToExclude {
388 return true
389 }
390 }
391 return false
392}
393
394func GetOfbFields(flow *ofp.OfpFlowStats, exclude ...ofp.OxmOfbFieldTypes) []*ofp.OfpOxmOfbField {
395 if flow == nil || flow.Match == nil || flow.Match.Type != ofp.OfpMatchType_OFPMT_OXM {
396 return nil
397 }
398 ofbFields := make([]*ofp.OfpOxmOfbField, 0)
399 for _, field := range flow.Match.OxmFields {
400 if field.OxmClass == ofp.OfpOxmClass_OFPXMC_OPENFLOW_BASIC {
401 ofbFields = append(ofbFields, field.GetOfbField())
402 }
403 }
404 if len(exclude) == 0 {
405 return ofbFields
406 } else {
407 filteredFields := make([]*ofp.OfpOxmOfbField, 0)
408 for _, ofbField := range ofbFields {
409 if !excludeOxmOfbField(ofbField, exclude...) {
410 filteredFields = append(filteredFields, ofbField)
411 }
412 }
413 return filteredFields
414 }
415}
416
417func GetPacketOutPort(packet *ofp.OfpPacketOut) uint32 {
418 if packet == nil {
419 return 0
420 }
421 for _, action := range packet.GetActions() {
422 if action.Type == OUTPUT {
423 return action.GetOutput().Port
424 }
425 }
426 return 0
427}
428
429func GetOutPort(flow *ofp.OfpFlowStats) uint32 {
430 if flow == nil {
431 return 0
432 }
433 for _, action := range GetActions(flow) {
434 if action.Type == OUTPUT {
435 out := action.GetOutput()
436 if out == nil {
437 return 0
438 }
439 return out.GetPort()
440 }
441 }
442 return 0
443}
444
445func GetInPort(flow *ofp.OfpFlowStats) uint32 {
446 if flow == nil {
447 return 0
448 }
449 for _, field := range GetOfbFields(flow) {
450 if field.Type == IN_PORT {
451 return field.GetPort()
452 }
453 }
454 return 0
455}
456
457func GetGotoTableId(flow *ofp.OfpFlowStats) uint32 {
458 if flow == nil {
459 return 0
460 }
461 for _, instruction := range flow.Instructions {
462 if instruction.Type == uint32(ofp.OfpInstructionType_OFPIT_GOTO_TABLE) {
463 gotoTable := instruction.GetGotoTable()
464 if gotoTable == nil {
465 return 0
466 }
467 return gotoTable.GetTableId()
468 }
469 }
470 return 0
471}
472
473func GetMeterId(flow *ofp.OfpFlowStats) uint32 {
474 if flow == nil {
475 return 0
476 }
477 for _, instruction := range flow.Instructions {
478 if instruction.Type == uint32(ofp.OfpInstructionType_OFPIT_METER) {
479 MeterInstruction := instruction.GetMeter()
480 if MeterInstruction == nil {
481 return 0
482 }
483 return MeterInstruction.GetMeterId()
484 }
485 }
486 return 0
487}
488
489func GetVlanVid(flow *ofp.OfpFlowStats) *uint32 {
490 if flow == nil {
491 return nil
492 }
493 for _, field := range GetOfbFields(flow) {
494 if field.Type == VLAN_VID {
495 ret := field.GetVlanVid()
496 return &ret
497 }
498 }
499 // Dont return 0 if the field is missing as vlan id value 0 has meaning and cannot be overloaded as "not found"
500 return nil
501}
502
Girish Gowdra03fd36c2020-06-11 13:32:29 -0700503func GetSetActionField(ctx context.Context, flow *ofp.OfpFlowStats, ofbType ofp.OxmOfbFieldTypes) (uint32, bool) {
504 if flow == nil {
505 return 0, false
506 }
507 for _, instruction := range flow.Instructions {
508 if instruction.Type == uint32(APPLY_ACTIONS) {
509 actions := instruction.GetActions()
510 for _, action := range actions.GetActions() {
511 if action.Type == SET_FIELD {
512 setField := action.GetSetField()
513 if setField.Field.GetOfbField().Type == ofbType {
514 switch ofbType {
515 case VLAN_PCP:
516 return setField.Field.GetOfbField().GetVlanPcp(), true
517 case VLAN_VID:
518 return setField.Field.GetOfbField().GetVlanVid(), true
519 default:
520 logger.Errorw(ctx, "unsupported-ofb-field-type", log.Fields{"ofbType": ofbType})
521 return 0, false
522 }
523 }
524 }
525 }
526 return 0, false
527 }
528 }
529 return 0, false
530}
531
Scott Baker456b8932019-10-24 10:36:39 -0700532func GetTunnelId(flow *ofp.OfpFlowStats) uint64 {
533 if flow == nil {
534 return 0
535 }
536 for _, field := range GetOfbFields(flow) {
537 if field.Type == TUNNEL_ID {
538 return field.GetTunnelId()
539 }
540 }
541 return 0
542}
543
Joey Armstrong7f8436c2023-07-09 20:23:27 -0400544// GetMetaData - legacy get method (only want lower 32 bits)
Neha Sharma94f16a92020-06-26 04:17:55 +0000545func GetMetaData(ctx context.Context, flow *ofp.OfpFlowStats) uint32 {
Scott Baker456b8932019-10-24 10:36:39 -0700546 if flow == nil {
547 return 0
548 }
549 for _, field := range GetOfbFields(flow) {
550 if field.Type == METADATA {
551 return uint32(field.GetTableMetadata() & 0xFFFFFFFF)
552 }
553 }
Neha Sharma94f16a92020-06-26 04:17:55 +0000554 logger.Debug(ctx, "No-metadata-present")
Scott Baker456b8932019-10-24 10:36:39 -0700555 return 0
556}
557
Neha Sharma94f16a92020-06-26 04:17:55 +0000558func GetMetaData64Bit(ctx context.Context, flow *ofp.OfpFlowStats) uint64 {
Scott Baker456b8932019-10-24 10:36:39 -0700559 if flow == nil {
560 return 0
561 }
562 for _, field := range GetOfbFields(flow) {
563 if field.Type == METADATA {
564 return field.GetTableMetadata()
565 }
566 }
Neha Sharma94f16a92020-06-26 04:17:55 +0000567 logger.Debug(ctx, "No-metadata-present")
Scott Baker456b8932019-10-24 10:36:39 -0700568 return 0
569}
570
571// function returns write metadata value from write_metadata action field
Neha Sharma94f16a92020-06-26 04:17:55 +0000572func GetMetadataFromWriteMetadataAction(ctx context.Context, flow *ofp.OfpFlowStats) uint64 {
Scott Baker456b8932019-10-24 10:36:39 -0700573 if flow != nil {
574 for _, instruction := range flow.Instructions {
575 if instruction.Type == uint32(WRITE_METADATA) {
576 if writeMetadata := instruction.GetWriteMetadata(); writeMetadata != nil {
577 return writeMetadata.GetMetadata()
578 }
579 }
580 }
581 }
Neha Sharma94f16a92020-06-26 04:17:55 +0000582 logger.Debugw(ctx, "No-write-metadata-present", log.Fields{"flow": flow})
Scott Baker456b8932019-10-24 10:36:39 -0700583 return 0
584}
585
Neha Sharma94f16a92020-06-26 04:17:55 +0000586func GetTechProfileIDFromWriteMetaData(ctx context.Context, metadata uint64) uint16 {
Scott Baker456b8932019-10-24 10:36:39 -0700587 /*
588 Write metadata instruction value (metadata) is 8 bytes:
589 MS 2 bytes: C Tag
590 Next 2 bytes: Technology Profile Id
591 Next 4 bytes: Port number (uni or nni)
592
593 This is set in the ONOS OltPipeline as a write metadata instruction
594 */
595 var tpId uint16 = 0
Neha Sharma94f16a92020-06-26 04:17:55 +0000596 logger.Debugw(ctx, "Write metadata value for Techprofile ID", log.Fields{"metadata": metadata})
Scott Baker456b8932019-10-24 10:36:39 -0700597 if metadata != 0 {
598 tpId = uint16((metadata >> 32) & 0xFFFF)
Neha Sharma94f16a92020-06-26 04:17:55 +0000599 logger.Debugw(ctx, "Found techprofile ID from write metadata action", log.Fields{"tpid": tpId})
Scott Baker456b8932019-10-24 10:36:39 -0700600 }
601 return tpId
602}
603
Neha Sharma94f16a92020-06-26 04:17:55 +0000604func GetEgressPortNumberFromWriteMetadata(ctx context.Context, flow *ofp.OfpFlowStats) uint32 {
Scott Baker456b8932019-10-24 10:36:39 -0700605 /*
606 Write metadata instruction value (metadata) is 8 bytes:
607 MS 2 bytes: C Tag
608 Next 2 bytes: Technology Profile Id
609 Next 4 bytes: Port number (uni or nni)
610 This is set in the ONOS OltPipeline as a write metadata instruction
611 */
612 var uniPort uint32 = 0
Neha Sharma94f16a92020-06-26 04:17:55 +0000613 md := GetMetadataFromWriteMetadataAction(ctx, flow)
614 logger.Debugw(ctx, "Metadata found for egress/uni port ", log.Fields{"metadata": md})
Scott Baker456b8932019-10-24 10:36:39 -0700615 if md != 0 {
616 uniPort = uint32(md & 0xFFFFFFFF)
Neha Sharma94f16a92020-06-26 04:17:55 +0000617 logger.Debugw(ctx, "Found EgressPort from write metadata action", log.Fields{"egress_port": uniPort})
Scott Baker456b8932019-10-24 10:36:39 -0700618 }
619 return uniPort
620
621}
622
Neha Sharma94f16a92020-06-26 04:17:55 +0000623func GetInnerTagFromMetaData(ctx context.Context, flow *ofp.OfpFlowStats) uint16 {
Scott Baker456b8932019-10-24 10:36:39 -0700624 /*
625 Write metadata instruction value (metadata) is 8 bytes:
626 MS 2 bytes: C Tag
627 Next 2 bytes: Technology Profile Id
628 Next 4 bytes: Port number (uni or nni)
629 This is set in the ONOS OltPipeline as a write metadata instruction
630 */
631 var innerTag uint16 = 0
Neha Sharma94f16a92020-06-26 04:17:55 +0000632 md := GetMetadataFromWriteMetadataAction(ctx, flow)
Scott Baker456b8932019-10-24 10:36:39 -0700633 if md != 0 {
634 innerTag = uint16((md >> 48) & 0xFFFF)
Neha Sharma94f16a92020-06-26 04:17:55 +0000635 logger.Debugw(ctx, "Found CVLAN from write metadate action", log.Fields{"c_vlan": innerTag})
Scott Baker456b8932019-10-24 10:36:39 -0700636 }
637 return innerTag
638}
639
Abhilash Laxmeshwar42f4ca02022-02-22 17:43:57 +0530640func GetInnerTagFromWriteMetaData(ctx context.Context, metadata uint64) uint16 {
641 /*
642 Write metadata instruction value (metadata) is 8 bytes:
643 MS 2 bytes: C Tag
644 Next 2 bytes: Technology Profile Id
645 Next 4 bytes: Port number (uni or nni)
646 This is set in the ONOS OltPipeline as a write metadata instruction
647 */
648 var innerTag uint16 = 0
649 if metadata != 0 {
650 innerTag = uint16((metadata >> 48) & 0xFFFF)
651 logger.Debugw(ctx, "Found CVLAN from write metadate action", log.Fields{"c_vlan": innerTag})
652 }
653 return innerTag
654}
655
Scott Baker456b8932019-10-24 10:36:39 -0700656//GetInnerTagFromMetaData retrieves the inner tag from the Metadata_ofp. The port number (UNI on ONU) is in the
657// lower 32-bits of Metadata_ofp and the inner_tag is in the upper 32-bits. This is set in the ONOS OltPipeline as
658//// a Metadata_ofp field
659/*func GetInnerTagFromMetaData(flow *ofp.OfpFlowStats) uint64 {
660 md := GetMetaData64Bit(flow)
661 if md == 0 {
662 return 0
663 }
664 if md <= 0xffffffff {
Neha Sharma94f16a92020-06-26 04:17:55 +0000665 logger.Debugw(ctx, "onos-upgrade-suggested", logger.Fields{"Metadata_ofp": md, "message": "Legacy MetaData detected form OltPipeline"})
Scott Baker456b8932019-10-24 10:36:39 -0700666 return md
667 }
668 return (md >> 32) & 0xffffffff
669}*/
670
671// Extract the child device port from a flow that contains the parent device peer port. Typically the UNI port of an
672// ONU child device. Per TST agreement this will be the lower 32 bits of tunnel id reserving upper 32 bits for later
673// use
674func GetChildPortFromTunnelId(flow *ofp.OfpFlowStats) uint32 {
675 tid := GetTunnelId(flow)
676 if tid == 0 {
677 return 0
678 }
679 // Per TST agreement we are keeping any child port id (uni port id) in the lower 32 bits
680 return uint32(tid & 0xffffffff)
681}
682
683func HasNextTable(flow *ofp.OfpFlowStats) bool {
684 if flow == nil {
685 return false
686 }
687 return GetGotoTableId(flow) != 0
688}
689
690func GetGroup(flow *ofp.OfpFlowStats) uint32 {
691 if flow == nil {
692 return 0
693 }
694 for _, action := range GetActions(flow) {
695 if action.Type == GROUP {
696 grp := action.GetGroup()
697 if grp == nil {
698 return 0
699 }
700 return grp.GetGroupId()
701 }
702 }
703 return 0
704}
705
706func HasGroup(flow *ofp.OfpFlowStats) bool {
707 return GetGroup(flow) != 0
708}
709
710// GetNextTableId returns the next table ID if the "table_id" is present in the map, otherwise return nil
711func GetNextTableId(kw OfpFlowModArgs) *uint32 {
712 if val, exist := kw["table_id"]; exist {
713 ret := uint32(val)
714 return &ret
715 }
716 return nil
717}
718
719// GetMeterIdFlowModArgs returns the meterId if the "meter_id" is present in the map, otherwise return 0
720func GetMeterIdFlowModArgs(kw OfpFlowModArgs) uint32 {
721 if val, exist := kw["meter_id"]; exist {
722 return uint32(val)
723 }
724 return 0
725}
726
727// Function returns the metadata if the "write_metadata" is present in the map, otherwise return nil
728func GetMetadataFlowModArgs(kw OfpFlowModArgs) uint64 {
729 if val, exist := kw["write_metadata"]; exist {
730 ret := uint64(val)
731 return ret
732 }
733 return 0
734}
735
Kent Hagermanf9cbe692020-05-05 17:50:26 -0400736// HashFlowStats returns a unique 64-bit integer hash of 'table_id', 'priority', and 'match'
737// The OF spec states that:
738// A flow table entry is identified by its match fields and priority: the match fields
739// and priority taken together identify a unique flow entry in the flow table.
Scott Baker6256a342020-02-21 15:36:26 -0800740func HashFlowStats(flow *ofp.OfpFlowStats) (uint64, error) {
Kent Hagermanf9cbe692020-05-05 17:50:26 -0400741 // first we need to make sure the oxm fields are in a predictable order (the specific order doesn't matter)
742 sort.Slice(flow.Match.OxmFields, func(a, b int) bool {
743 fieldsA, fieldsB := flow.Match.OxmFields[a], flow.Match.OxmFields[b]
744 if fieldsA.OxmClass < fieldsB.OxmClass {
745 return true
746 }
747 switch fieldA := fieldsA.Field.(type) {
748 case *ofp.OfpOxmField_OfbField:
749 switch fieldB := fieldsB.Field.(type) {
750 case *ofp.OfpOxmField_ExperimenterField:
751 return true // ofp < experimenter
752 case *ofp.OfpOxmField_OfbField:
753 return fieldA.OfbField.Type < fieldB.OfbField.Type
754 }
755 case *ofp.OfpOxmField_ExperimenterField:
756 switch fieldB := fieldsB.Field.(type) {
757 case *ofp.OfpOxmField_OfbField:
758 return false // ofp < experimenter
759 case *ofp.OfpOxmField_ExperimenterField:
760 eFieldA, eFieldB := fieldA.ExperimenterField, fieldB.ExperimenterField
761 if eFieldA.Experimenter != eFieldB.Experimenter {
762 return eFieldA.Experimenter < eFieldB.Experimenter
763 }
764 return eFieldA.OxmHeader < eFieldB.OxmHeader
765 }
766 }
767 return false
768 })
769
770 md5Hash := md5.New() // note that write errors will never occur with md5 hashing
771 var tmp [12]byte
772
773 binary.BigEndian.PutUint32(tmp[0:4], flow.TableId) // tableId
774 binary.BigEndian.PutUint32(tmp[4:8], flow.Priority) // priority
775 binary.BigEndian.PutUint32(tmp[8:12], uint32(flow.Match.Type)) // match type
776 _, _ = md5Hash.Write(tmp[:12])
777
778 for _, field := range flow.Match.OxmFields { // for all match fields
779 binary.BigEndian.PutUint32(tmp[:4], uint32(field.OxmClass)) // match class
780 _, _ = md5Hash.Write(tmp[:4])
781
782 switch oxmField := field.Field.(type) {
783 case *ofp.OfpOxmField_ExperimenterField:
784 binary.BigEndian.PutUint32(tmp[0:4], oxmField.ExperimenterField.Experimenter)
785 binary.BigEndian.PutUint32(tmp[4:8], oxmField.ExperimenterField.OxmHeader)
786 _, _ = md5Hash.Write(tmp[:8])
787
788 case *ofp.OfpOxmField_OfbField:
789 if err := hashWriteOfbField(md5Hash, oxmField.OfbField); err != nil {
790 return 0, err
791 }
792
793 default:
794 return 0, fmt.Errorf("unknown OfpOxmField type: %T", field.Field)
795 }
Scott Baker456b8932019-10-24 10:36:39 -0700796 }
Kent Hagermanf9cbe692020-05-05 17:50:26 -0400797
798 ret := md5Hash.Sum(nil)
799 return binary.BigEndian.Uint64(ret[0:8]), nil
800}
801
802func hashWriteOfbField(md5Hash hash.Hash, field *ofp.OfpOxmOfbField) error {
803 var tmp [8]byte
804 binary.BigEndian.PutUint32(tmp[:4], uint32(field.Type)) // type
805 _, _ = md5Hash.Write(tmp[:4])
806
807 // value
808 valType, val32, val64, valSlice := uint8(0), uint32(0), uint64(0), []byte(nil)
809 switch val := field.Value.(type) {
810 case *ofp.OfpOxmOfbField_Port:
811 valType, val32 = 4, val.Port
812 case *ofp.OfpOxmOfbField_PhysicalPort:
813 valType, val32 = 4, val.PhysicalPort
814 case *ofp.OfpOxmOfbField_TableMetadata:
815 valType, val64 = 8, val.TableMetadata
816 case *ofp.OfpOxmOfbField_EthDst:
817 valType, valSlice = 1, val.EthDst
818 case *ofp.OfpOxmOfbField_EthSrc:
819 valType, valSlice = 1, val.EthSrc
820 case *ofp.OfpOxmOfbField_EthType:
821 valType, val32 = 4, val.EthType
822 case *ofp.OfpOxmOfbField_VlanVid:
823 valType, val32 = 4, val.VlanVid
824 case *ofp.OfpOxmOfbField_VlanPcp:
825 valType, val32 = 4, val.VlanPcp
826 case *ofp.OfpOxmOfbField_IpDscp:
827 valType, val32 = 4, val.IpDscp
828 case *ofp.OfpOxmOfbField_IpEcn:
829 valType, val32 = 4, val.IpEcn
830 case *ofp.OfpOxmOfbField_IpProto:
831 valType, val32 = 4, val.IpProto
832 case *ofp.OfpOxmOfbField_Ipv4Src:
833 valType, val32 = 4, val.Ipv4Src
834 case *ofp.OfpOxmOfbField_Ipv4Dst:
835 valType, val32 = 4, val.Ipv4Dst
836 case *ofp.OfpOxmOfbField_TcpSrc:
837 valType, val32 = 4, val.TcpSrc
838 case *ofp.OfpOxmOfbField_TcpDst:
839 valType, val32 = 4, val.TcpDst
840 case *ofp.OfpOxmOfbField_UdpSrc:
841 valType, val32 = 4, val.UdpSrc
842 case *ofp.OfpOxmOfbField_UdpDst:
843 valType, val32 = 4, val.UdpDst
844 case *ofp.OfpOxmOfbField_SctpSrc:
845 valType, val32 = 4, val.SctpSrc
846 case *ofp.OfpOxmOfbField_SctpDst:
847 valType, val32 = 4, val.SctpDst
848 case *ofp.OfpOxmOfbField_Icmpv4Type:
849 valType, val32 = 4, val.Icmpv4Type
850 case *ofp.OfpOxmOfbField_Icmpv4Code:
851 valType, val32 = 4, val.Icmpv4Code
852 case *ofp.OfpOxmOfbField_ArpOp:
853 valType, val32 = 4, val.ArpOp
854 case *ofp.OfpOxmOfbField_ArpSpa:
855 valType, val32 = 4, val.ArpSpa
856 case *ofp.OfpOxmOfbField_ArpTpa:
857 valType, val32 = 4, val.ArpTpa
858 case *ofp.OfpOxmOfbField_ArpSha:
859 valType, valSlice = 1, val.ArpSha
860 case *ofp.OfpOxmOfbField_ArpTha:
861 valType, valSlice = 1, val.ArpTha
862 case *ofp.OfpOxmOfbField_Ipv6Src:
863 valType, valSlice = 1, val.Ipv6Src
864 case *ofp.OfpOxmOfbField_Ipv6Dst:
865 valType, valSlice = 1, val.Ipv6Dst
866 case *ofp.OfpOxmOfbField_Ipv6Flabel:
867 valType, val32 = 4, val.Ipv6Flabel
868 case *ofp.OfpOxmOfbField_Icmpv6Type:
869 valType, val32 = 4, val.Icmpv6Type
870 case *ofp.OfpOxmOfbField_Icmpv6Code:
871 valType, val32 = 4, val.Icmpv6Code
872 case *ofp.OfpOxmOfbField_Ipv6NdTarget:
873 valType, valSlice = 1, val.Ipv6NdTarget
874 case *ofp.OfpOxmOfbField_Ipv6NdSsl:
875 valType, valSlice = 1, val.Ipv6NdSsl
876 case *ofp.OfpOxmOfbField_Ipv6NdTll:
877 valType, valSlice = 1, val.Ipv6NdTll
878 case *ofp.OfpOxmOfbField_MplsLabel:
879 valType, val32 = 4, val.MplsLabel
880 case *ofp.OfpOxmOfbField_MplsTc:
881 valType, val32 = 4, val.MplsTc
882 case *ofp.OfpOxmOfbField_MplsBos:
883 valType, val32 = 4, val.MplsBos
884 case *ofp.OfpOxmOfbField_PbbIsid:
885 valType, val32 = 4, val.PbbIsid
886 case *ofp.OfpOxmOfbField_TunnelId:
887 valType, val64 = 8, val.TunnelId
888 case *ofp.OfpOxmOfbField_Ipv6Exthdr:
889 valType, val32 = 4, val.Ipv6Exthdr
890 default:
891 return fmt.Errorf("unknown OfpOxmField value type: %T", val)
Scott Baker456b8932019-10-24 10:36:39 -0700892 }
Kent Hagermanf9cbe692020-05-05 17:50:26 -0400893 switch valType {
894 case 1: // slice
895 _, _ = md5Hash.Write(valSlice)
896 case 4: // uint32
897 binary.BigEndian.PutUint32(tmp[:4], val32)
898 _, _ = md5Hash.Write(tmp[:4])
899 case 8: // uint64
900 binary.BigEndian.PutUint64(tmp[:8], val64)
901 _, _ = md5Hash.Write(tmp[:8])
David K. Bainbridge7c75cac2020-02-19 08:53:46 -0800902 }
Kent Hagermanf9cbe692020-05-05 17:50:26 -0400903
904 // mask
905 if !field.HasMask {
906 tmp[0] = 0x00
907 _, _ = md5Hash.Write(tmp[:1]) // match hasMask = false
908 } else {
909 tmp[0] = 0x01
910 _, _ = md5Hash.Write(tmp[:1]) // match hasMask = true
911
912 maskType, mask32, mask64, maskSlice := uint8(0), uint32(0), uint64(0), []byte(nil)
913 switch mask := field.Mask.(type) {
914 case *ofp.OfpOxmOfbField_TableMetadataMask:
915 maskType, mask64 = 8, mask.TableMetadataMask
916 case *ofp.OfpOxmOfbField_EthDstMask:
917 maskType, maskSlice = 1, mask.EthDstMask
918 case *ofp.OfpOxmOfbField_EthSrcMask:
919 maskType, maskSlice = 1, mask.EthSrcMask
920 case *ofp.OfpOxmOfbField_VlanVidMask:
921 maskType, mask32 = 4, mask.VlanVidMask
922 case *ofp.OfpOxmOfbField_Ipv4SrcMask:
923 maskType, mask32 = 4, mask.Ipv4SrcMask
924 case *ofp.OfpOxmOfbField_Ipv4DstMask:
925 maskType, mask32 = 4, mask.Ipv4DstMask
926 case *ofp.OfpOxmOfbField_ArpSpaMask:
927 maskType, mask32 = 4, mask.ArpSpaMask
928 case *ofp.OfpOxmOfbField_ArpTpaMask:
929 maskType, mask32 = 4, mask.ArpTpaMask
930 case *ofp.OfpOxmOfbField_Ipv6SrcMask:
931 maskType, maskSlice = 1, mask.Ipv6SrcMask
932 case *ofp.OfpOxmOfbField_Ipv6DstMask:
933 maskType, maskSlice = 1, mask.Ipv6DstMask
934 case *ofp.OfpOxmOfbField_Ipv6FlabelMask:
935 maskType, mask32 = 4, mask.Ipv6FlabelMask
936 case *ofp.OfpOxmOfbField_PbbIsidMask:
937 maskType, mask32 = 4, mask.PbbIsidMask
938 case *ofp.OfpOxmOfbField_TunnelIdMask:
939 maskType, mask64 = 8, mask.TunnelIdMask
940 case *ofp.OfpOxmOfbField_Ipv6ExthdrMask:
941 maskType, mask32 = 4, mask.Ipv6ExthdrMask
942 case nil:
943 return fmt.Errorf("hasMask set to true, but no mask present")
944 default:
945 return fmt.Errorf("unknown OfpOxmField mask type: %T", mask)
946 }
947 switch maskType {
948 case 1: // slice
949 _, _ = md5Hash.Write(maskSlice)
950 case 4: // uint32
951 binary.BigEndian.PutUint32(tmp[:4], mask32)
952 _, _ = md5Hash.Write(tmp[:4])
953 case 8: // uint64
954 binary.BigEndian.PutUint64(tmp[:8], mask64)
955 _, _ = md5Hash.Write(tmp[:8])
956 }
957 }
958 return nil
Scott Baker456b8932019-10-24 10:36:39 -0700959}
960
961// flowStatsEntryFromFlowModMessage maps an ofp_flow_mod message to an ofp_flow_stats message
Scott Baker6256a342020-02-21 15:36:26 -0800962func FlowStatsEntryFromFlowModMessage(mod *ofp.OfpFlowMod) (*ofp.OfpFlowStats, error) {
Scott Baker456b8932019-10-24 10:36:39 -0700963 flow := &ofp.OfpFlowStats{}
964 if mod == nil {
Scott Baker6256a342020-02-21 15:36:26 -0800965 return flow, nil
Scott Baker456b8932019-10-24 10:36:39 -0700966 }
967 flow.TableId = mod.TableId
968 flow.Priority = mod.Priority
969 flow.IdleTimeout = mod.IdleTimeout
970 flow.HardTimeout = mod.HardTimeout
971 flow.Flags = mod.Flags
972 flow.Cookie = mod.Cookie
973 flow.Match = mod.Match
974 flow.Instructions = mod.Instructions
Scott Baker6256a342020-02-21 15:36:26 -0800975 var err error
976 if flow.Id, err = HashFlowStats(flow); err != nil {
977 return nil, err
978 }
979
980 return flow, nil
Scott Baker456b8932019-10-24 10:36:39 -0700981}
982
983func GroupEntryFromGroupMod(mod *ofp.OfpGroupMod) *ofp.OfpGroupEntry {
984 group := &ofp.OfpGroupEntry{}
985 if mod == nil {
986 return group
987 }
988 group.Desc = &ofp.OfpGroupDesc{Type: mod.Type, GroupId: mod.GroupId, Buckets: mod.Buckets}
989 group.Stats = &ofp.OfpGroupStats{GroupId: mod.GroupId}
990 //TODO do we need to instantiate bucket bins?
991 return group
992}
993
994// flowStatsEntryFromFlowModMessage maps an ofp_flow_mod message to an ofp_flow_stats message
Neha Sharma94f16a92020-06-26 04:17:55 +0000995func MeterEntryFromMeterMod(ctx context.Context, meterMod *ofp.OfpMeterMod) *ofp.OfpMeterEntry {
Scott Baker456b8932019-10-24 10:36:39 -0700996 bandStats := make([]*ofp.OfpMeterBandStats, 0)
997 meter := &ofp.OfpMeterEntry{Config: &ofp.OfpMeterConfig{},
998 Stats: &ofp.OfpMeterStats{BandStats: bandStats}}
999 if meterMod == nil {
Neha Sharma94f16a92020-06-26 04:17:55 +00001000 logger.Error(ctx, "Invalid meter mod command")
Scott Baker456b8932019-10-24 10:36:39 -07001001 return meter
1002 }
1003 // config init
1004 meter.Config.MeterId = meterMod.MeterId
1005 meter.Config.Flags = meterMod.Flags
1006 meter.Config.Bands = meterMod.Bands
1007 // meter stats init
1008 meter.Stats.MeterId = meterMod.MeterId
1009 meter.Stats.FlowCount = 0
1010 meter.Stats.PacketInCount = 0
1011 meter.Stats.ByteInCount = 0
1012 meter.Stats.DurationSec = 0
1013 meter.Stats.DurationNsec = 0
1014 // band stats init
David K. Bainbridge7c75cac2020-02-19 08:53:46 -08001015 for range meterMod.Bands {
Scott Baker456b8932019-10-24 10:36:39 -07001016 band := &ofp.OfpMeterBandStats{}
1017 band.PacketBandCount = 0
1018 band.ByteBandCount = 0
1019 bandStats = append(bandStats, band)
1020 }
1021 meter.Stats.BandStats = bandStats
Neha Sharma94f16a92020-06-26 04:17:55 +00001022 logger.Debugw(ctx, "Allocated meter entry", log.Fields{"meter": *meter})
Scott Baker456b8932019-10-24 10:36:39 -07001023 return meter
1024
1025}
1026
1027func GetMeterIdFromFlow(flow *ofp.OfpFlowStats) uint32 {
1028 if flow != nil {
1029 for _, instruction := range flow.Instructions {
1030 if instruction.Type == uint32(METER_ACTION) {
1031 if meterInst := instruction.GetMeter(); meterInst != nil {
1032 return meterInst.GetMeterId()
1033 }
1034 }
1035 }
1036 }
1037
1038 return uint32(0)
1039}
1040
1041func MkOxmFields(matchFields []ofp.OfpOxmField) []*ofp.OfpOxmField {
1042 oxmFields := make([]*ofp.OfpOxmField, 0)
1043 for _, matchField := range matchFields {
1044 oxmField := ofp.OfpOxmField{OxmClass: ofp.OfpOxmClass_OFPXMC_OPENFLOW_BASIC, Field: matchField.Field}
1045 oxmFields = append(oxmFields, &oxmField)
1046 }
1047 return oxmFields
1048}
1049
1050func MkInstructionsFromActions(actions []*ofp.OfpAction) []*ofp.OfpInstruction {
1051 instructions := make([]*ofp.OfpInstruction, 0)
1052 instructionAction := ofp.OfpInstruction_Actions{Actions: &ofp.OfpInstructionActions{Actions: actions}}
1053 instruction := ofp.OfpInstruction{Type: uint32(APPLY_ACTIONS), Data: &instructionAction}
1054 instructions = append(instructions, &instruction)
1055 return instructions
1056}
1057
1058// Convenience function to generare ofp_flow_mod message with OXM BASIC match composed from the match_fields, and
1059// single APPLY_ACTIONS instruction with a list if ofp_action objects.
1060func MkSimpleFlowMod(matchFields []*ofp.OfpOxmField, actions []*ofp.OfpAction, command *ofp.OfpFlowModCommand, kw OfpFlowModArgs) *ofp.OfpFlowMod {
1061
1062 // Process actions instructions
1063 instructions := make([]*ofp.OfpInstruction, 0)
1064 instructionAction := ofp.OfpInstruction_Actions{Actions: &ofp.OfpInstructionActions{Actions: actions}}
1065 instruction := ofp.OfpInstruction{Type: uint32(APPLY_ACTIONS), Data: &instructionAction}
1066 instructions = append(instructions, &instruction)
1067
1068 // Process next table
1069 if tableId := GetNextTableId(kw); tableId != nil {
1070 var instGotoTable ofp.OfpInstruction_GotoTable
1071 instGotoTable.GotoTable = &ofp.OfpInstructionGotoTable{TableId: *tableId}
1072 inst := ofp.OfpInstruction{Type: uint32(ofp.OfpInstructionType_OFPIT_GOTO_TABLE), Data: &instGotoTable}
1073 instructions = append(instructions, &inst)
1074 }
1075 // Process meter action
1076 if meterId := GetMeterIdFlowModArgs(kw); meterId != 0 {
1077 var instMeter ofp.OfpInstruction_Meter
1078 instMeter.Meter = &ofp.OfpInstructionMeter{MeterId: meterId}
1079 inst := ofp.OfpInstruction{Type: uint32(METER_ACTION), Data: &instMeter}
1080 instructions = append(instructions, &inst)
1081 }
1082 //process write_metadata action
1083 if metadata := GetMetadataFlowModArgs(kw); metadata != 0 {
1084 var instWriteMetadata ofp.OfpInstruction_WriteMetadata
1085 instWriteMetadata.WriteMetadata = &ofp.OfpInstructionWriteMetadata{Metadata: metadata}
1086 inst := ofp.OfpInstruction{Type: uint32(WRITE_METADATA), Data: &instWriteMetadata}
1087 instructions = append(instructions, &inst)
1088 }
1089
1090 // Process match fields
1091 oxmFields := make([]*ofp.OfpOxmField, 0)
1092 for _, matchField := range matchFields {
1093 oxmField := ofp.OfpOxmField{OxmClass: ofp.OfpOxmClass_OFPXMC_OPENFLOW_BASIC, Field: matchField.Field}
1094 oxmFields = append(oxmFields, &oxmField)
1095 }
1096 var match ofp.OfpMatch
1097 match.Type = ofp.OfpMatchType_OFPMT_OXM
1098 match.OxmFields = oxmFields
1099
1100 // Create ofp_flow_message
1101 msg := &ofp.OfpFlowMod{}
1102 if command == nil {
1103 msg.Command = ofp.OfpFlowModCommand_OFPFC_ADD
1104 } else {
1105 msg.Command = *command
1106 }
1107 msg.Instructions = instructions
1108 msg.Match = &match
1109
1110 // Set the variadic argument values
1111 msg = setVariadicModAttributes(msg, kw)
1112
1113 return msg
1114}
1115
1116func MkMulticastGroupMod(groupId uint32, buckets []*ofp.OfpBucket, command *ofp.OfpGroupModCommand) *ofp.OfpGroupMod {
1117 group := &ofp.OfpGroupMod{}
1118 if command == nil {
1119 group.Command = ofp.OfpGroupModCommand_OFPGC_ADD
1120 } else {
1121 group.Command = *command
1122 }
1123 group.Type = ofp.OfpGroupType_OFPGT_ALL
1124 group.GroupId = groupId
1125 group.Buckets = buckets
1126 return group
1127}
1128
Joey Armstrong7f8436c2023-07-09 20:23:27 -04001129// SetVariadicModAttributes sets only uint64 or uint32 fields of the ofp_flow_mod message
Scott Baker456b8932019-10-24 10:36:39 -07001130func setVariadicModAttributes(mod *ofp.OfpFlowMod, args OfpFlowModArgs) *ofp.OfpFlowMod {
1131 if args == nil {
1132 return mod
1133 }
1134 for key, val := range args {
1135 switch key {
1136 case "cookie":
1137 mod.Cookie = val
1138 case "cookie_mask":
1139 mod.CookieMask = val
1140 case "table_id":
1141 mod.TableId = uint32(val)
1142 case "idle_timeout":
1143 mod.IdleTimeout = uint32(val)
1144 case "hard_timeout":
1145 mod.HardTimeout = uint32(val)
1146 case "priority":
1147 mod.Priority = uint32(val)
1148 case "buffer_id":
1149 mod.BufferId = uint32(val)
1150 case "out_port":
1151 mod.OutPort = uint32(val)
1152 case "out_group":
1153 mod.OutGroup = uint32(val)
1154 case "flags":
1155 mod.Flags = uint32(val)
1156 }
1157 }
1158 return mod
1159}
1160
1161func MkPacketIn(port uint32, packet []byte) *ofp.OfpPacketIn {
1162 packetIn := &ofp.OfpPacketIn{
1163 Reason: ofp.OfpPacketInReason_OFPR_ACTION,
1164 Match: &ofp.OfpMatch{
1165 Type: ofp.OfpMatchType_OFPMT_OXM,
1166 OxmFields: []*ofp.OfpOxmField{
1167 {
1168 OxmClass: ofp.OfpOxmClass_OFPXMC_OPENFLOW_BASIC,
1169 Field: &ofp.OfpOxmField_OfbField{
1170 OfbField: InPort(port)},
1171 },
1172 },
1173 },
1174 Data: packet,
1175 }
1176 return packetIn
1177}
1178
1179// MkFlowStat is a helper method to build flows
Scott Baker6256a342020-02-21 15:36:26 -08001180func MkFlowStat(fa *FlowArgs) (*ofp.OfpFlowStats, error) {
Scott Baker456b8932019-10-24 10:36:39 -07001181 //Build the match-fields
1182 matchFields := make([]*ofp.OfpOxmField, 0)
1183 for _, val := range fa.MatchFields {
1184 matchFields = append(matchFields, &ofp.OfpOxmField{Field: &ofp.OfpOxmField_OfbField{OfbField: val}})
1185 }
1186 return FlowStatsEntryFromFlowModMessage(MkSimpleFlowMod(matchFields, fa.Actions, fa.Command, fa.KV))
1187}
1188
1189func MkGroupStat(ga *GroupArgs) *ofp.OfpGroupEntry {
1190 return GroupEntryFromGroupMod(MkMulticastGroupMod(ga.GroupId, ga.Buckets, ga.Command))
1191}
1192
1193type OfpFlowModArgs map[string]uint64
1194
1195type FlowArgs struct {
1196 MatchFields []*ofp.OfpOxmOfbField
1197 Actions []*ofp.OfpAction
1198 Command *ofp.OfpFlowModCommand
1199 Priority uint32
1200 KV OfpFlowModArgs
1201}
1202
1203type GroupArgs struct {
1204 GroupId uint32
1205 Buckets []*ofp.OfpBucket
1206 Command *ofp.OfpGroupModCommand
1207}
1208
1209type FlowsAndGroups struct {
1210 Flows *ordered_map.OrderedMap
1211 Groups *ordered_map.OrderedMap
1212}
1213
1214func NewFlowsAndGroups() *FlowsAndGroups {
1215 var fg FlowsAndGroups
1216 fg.Flows = ordered_map.NewOrderedMap()
1217 fg.Groups = ordered_map.NewOrderedMap()
1218 return &fg
1219}
1220
1221func (fg *FlowsAndGroups) Copy() *FlowsAndGroups {
1222 copyFG := NewFlowsAndGroups()
1223 iter := fg.Flows.IterFunc()
1224 for kv, ok := iter(); ok; kv, ok = iter() {
1225 if protoMsg, isMsg := kv.Value.(*ofp.OfpFlowStats); isMsg {
1226 copyFG.Flows.Set(kv.Key, proto.Clone(protoMsg))
1227 }
1228 }
1229 iter = fg.Groups.IterFunc()
1230 for kv, ok := iter(); ok; kv, ok = iter() {
1231 if protoMsg, isMsg := kv.Value.(*ofp.OfpGroupEntry); isMsg {
1232 copyFG.Groups.Set(kv.Key, proto.Clone(protoMsg))
1233 }
1234 }
1235 return copyFG
1236}
1237
1238func (fg *FlowsAndGroups) GetFlow(index int) *ofp.OfpFlowStats {
1239 iter := fg.Flows.IterFunc()
1240 pos := 0
1241 for kv, ok := iter(); ok; kv, ok = iter() {
1242 if pos == index {
1243 if protoMsg, isMsg := kv.Value.(*ofp.OfpFlowStats); isMsg {
1244 return protoMsg
1245 }
1246 return nil
1247 }
1248 pos += 1
1249 }
1250 return nil
1251}
1252
1253func (fg *FlowsAndGroups) ListFlows() []*ofp.OfpFlowStats {
1254 flows := make([]*ofp.OfpFlowStats, 0)
1255 iter := fg.Flows.IterFunc()
1256 for kv, ok := iter(); ok; kv, ok = iter() {
1257 if protoMsg, isMsg := kv.Value.(*ofp.OfpFlowStats); isMsg {
1258 flows = append(flows, protoMsg)
1259 }
1260 }
1261 return flows
1262}
1263
1264func (fg *FlowsAndGroups) ListGroups() []*ofp.OfpGroupEntry {
1265 groups := make([]*ofp.OfpGroupEntry, 0)
1266 iter := fg.Groups.IterFunc()
1267 for kv, ok := iter(); ok; kv, ok = iter() {
1268 if protoMsg, isMsg := kv.Value.(*ofp.OfpGroupEntry); isMsg {
1269 groups = append(groups, protoMsg)
1270 }
1271 }
1272 return groups
1273}
1274
1275func (fg *FlowsAndGroups) String() string {
1276 var buffer bytes.Buffer
1277 iter := fg.Flows.IterFunc()
1278 for kv, ok := iter(); ok; kv, ok = iter() {
1279 if protoMsg, isMsg := kv.Value.(*ofp.OfpFlowStats); isMsg {
1280 buffer.WriteString("\nFlow:\n")
1281 buffer.WriteString(proto.MarshalTextString(protoMsg))
1282 buffer.WriteString("\n")
1283 }
1284 }
1285 iter = fg.Groups.IterFunc()
1286 for kv, ok := iter(); ok; kv, ok = iter() {
1287 if protoMsg, isMsg := kv.Value.(*ofp.OfpGroupEntry); isMsg {
1288 buffer.WriteString("\nGroup:\n")
1289 buffer.WriteString(proto.MarshalTextString(protoMsg))
1290 buffer.WriteString("\n")
1291 }
1292 }
1293 return buffer.String()
1294}
1295
1296func (fg *FlowsAndGroups) AddFlow(flow *ofp.OfpFlowStats) {
1297 if flow == nil {
1298 return
1299 }
1300
1301 if fg.Flows == nil {
1302 fg.Flows = ordered_map.NewOrderedMap()
1303 }
1304 if fg.Groups == nil {
1305 fg.Groups = ordered_map.NewOrderedMap()
1306 }
1307 //Add flow only if absent
1308 if _, exist := fg.Flows.Get(flow.Id); !exist {
1309 fg.Flows.Set(flow.Id, flow)
1310 }
1311}
1312
1313func (fg *FlowsAndGroups) AddGroup(group *ofp.OfpGroupEntry) {
1314 if group == nil {
1315 return
1316 }
1317
1318 if fg.Flows == nil {
1319 fg.Flows = ordered_map.NewOrderedMap()
1320 }
1321 if fg.Groups == nil {
1322 fg.Groups = ordered_map.NewOrderedMap()
1323 }
1324 //Add group only if absent
1325 if _, exist := fg.Groups.Get(group.Desc.GroupId); !exist {
1326 fg.Groups.Set(group.Desc.GroupId, group)
1327 }
1328}
1329
Joey Armstrong7f8436c2023-07-09 20:23:27 -04001330// AddFrom add flows and groups from the argument into this structure only if they do not already exist
Scott Baker456b8932019-10-24 10:36:39 -07001331func (fg *FlowsAndGroups) AddFrom(from *FlowsAndGroups) {
1332 iter := from.Flows.IterFunc()
1333 for kv, ok := iter(); ok; kv, ok = iter() {
1334 if protoMsg, isMsg := kv.Value.(*ofp.OfpFlowStats); isMsg {
1335 if _, exist := fg.Flows.Get(protoMsg.Id); !exist {
1336 fg.Flows.Set(protoMsg.Id, protoMsg)
1337 }
1338 }
1339 }
1340 iter = from.Groups.IterFunc()
1341 for kv, ok := iter(); ok; kv, ok = iter() {
1342 if protoMsg, isMsg := kv.Value.(*ofp.OfpGroupEntry); isMsg {
1343 if _, exist := fg.Groups.Get(protoMsg.Stats.GroupId); !exist {
1344 fg.Groups.Set(protoMsg.Stats.GroupId, protoMsg)
1345 }
1346 }
1347 }
1348}
1349
1350type DeviceRules struct {
khenaidoo26721882021-08-11 17:42:52 -04001351 Rules map[string]*FlowsAndGroups
1352 rulesLock sync.RWMutex
Scott Baker456b8932019-10-24 10:36:39 -07001353}
1354
1355func NewDeviceRules() *DeviceRules {
1356 var dr DeviceRules
1357 dr.Rules = make(map[string]*FlowsAndGroups)
1358 return &dr
1359}
1360
1361func (dr *DeviceRules) Copy() *DeviceRules {
1362 copyDR := NewDeviceRules()
1363 if dr != nil {
khenaidoo26721882021-08-11 17:42:52 -04001364 dr.rulesLock.RLock()
1365 defer dr.rulesLock.RUnlock()
Scott Baker456b8932019-10-24 10:36:39 -07001366 for key, val := range dr.Rules {
1367 if val != nil {
1368 copyDR.Rules[key] = val.Copy()
1369 }
1370 }
1371 }
1372 return copyDR
1373}
1374
khenaidoo26721882021-08-11 17:42:52 -04001375func (dr *DeviceRules) Keys() []string {
1376 dr.rulesLock.RLock()
1377 defer dr.rulesLock.RUnlock()
1378 keys := make([]string, 0, len(dr.Rules))
1379 for k := range dr.Rules {
1380 keys = append(keys, k)
1381 }
1382 return keys
1383}
1384
Scott Baker456b8932019-10-24 10:36:39 -07001385func (dr *DeviceRules) ClearFlows(deviceId string) {
khenaidoo26721882021-08-11 17:42:52 -04001386 dr.rulesLock.Lock()
1387 defer dr.rulesLock.Unlock()
Scott Baker456b8932019-10-24 10:36:39 -07001388 if _, exist := dr.Rules[deviceId]; exist {
1389 dr.Rules[deviceId].Flows = ordered_map.NewOrderedMap()
1390 }
1391}
1392
1393func (dr *DeviceRules) FilterRules(deviceIds map[string]string) *DeviceRules {
1394 filteredDR := NewDeviceRules()
khenaidoo26721882021-08-11 17:42:52 -04001395 dr.rulesLock.RLock()
1396 defer dr.rulesLock.RUnlock()
Scott Baker456b8932019-10-24 10:36:39 -07001397 for key, val := range dr.Rules {
1398 if _, exist := deviceIds[key]; exist {
1399 filteredDR.Rules[key] = val.Copy()
1400 }
1401 }
1402 return filteredDR
1403}
1404
Elia Battiston02d5b642022-02-08 16:50:10 +01001405func (dr *DeviceRules) RemoveRule(deviceId string) {
1406 dr.rulesLock.RLock()
1407 defer dr.rulesLock.RUnlock()
1408 delete(dr.Rules, deviceId)
1409}
1410
Scott Baker456b8932019-10-24 10:36:39 -07001411func (dr *DeviceRules) AddFlow(deviceId string, flow *ofp.OfpFlowStats) {
khenaidoo26721882021-08-11 17:42:52 -04001412 dr.rulesLock.Lock()
1413 defer dr.rulesLock.Unlock()
Scott Baker456b8932019-10-24 10:36:39 -07001414 if _, exist := dr.Rules[deviceId]; !exist {
1415 dr.Rules[deviceId] = NewFlowsAndGroups()
1416 }
1417 dr.Rules[deviceId].AddFlow(flow)
1418}
1419
1420func (dr *DeviceRules) GetRules() map[string]*FlowsAndGroups {
khenaidoo26721882021-08-11 17:42:52 -04001421 dr.rulesLock.RLock()
1422 defer dr.rulesLock.RUnlock()
Scott Baker456b8932019-10-24 10:36:39 -07001423 return dr.Rules
1424}
1425
1426func (dr *DeviceRules) String() string {
1427 var buffer bytes.Buffer
khenaidoo26721882021-08-11 17:42:52 -04001428 dr.rulesLock.RLock()
1429 defer dr.rulesLock.RUnlock()
Scott Baker456b8932019-10-24 10:36:39 -07001430 for key, value := range dr.Rules {
1431 buffer.WriteString("DeviceId:")
1432 buffer.WriteString(key)
1433 buffer.WriteString(value.String())
1434 buffer.WriteString("\n\n")
1435 }
1436 return buffer.String()
1437}
1438
1439func (dr *DeviceRules) AddFlowsAndGroup(deviceId string, fg *FlowsAndGroups) {
khenaidoo26721882021-08-11 17:42:52 -04001440 dr.rulesLock.Lock()
1441 defer dr.rulesLock.Unlock()
Scott Baker456b8932019-10-24 10:36:39 -07001442 if _, ok := dr.Rules[deviceId]; !ok {
1443 dr.Rules[deviceId] = NewFlowsAndGroups()
1444 }
1445 dr.Rules[deviceId] = fg
1446}
1447
1448// CreateEntryIfNotExist creates a new deviceId in the Map if it does not exist and assigns an
1449// empty FlowsAndGroups to it. Otherwise, it does nothing.
1450func (dr *DeviceRules) CreateEntryIfNotExist(deviceId string) {
khenaidoo26721882021-08-11 17:42:52 -04001451 dr.rulesLock.Lock()
1452 defer dr.rulesLock.Unlock()
Scott Baker456b8932019-10-24 10:36:39 -07001453 if _, ok := dr.Rules[deviceId]; !ok {
1454 dr.Rules[deviceId] = NewFlowsAndGroups()
1455 }
1456}
1457
1458/*
1459 * Common flow routines
1460 */
1461
Joey Armstrong7f8436c2023-07-09 20:23:27 -04001462// FindOverlappingFlows return a list of overlapping flow(s) where mod is the flow request
Scott Baker456b8932019-10-24 10:36:39 -07001463func FindOverlappingFlows(flows []*ofp.OfpFlowStats, mod *ofp.OfpFlowMod) []*ofp.OfpFlowStats {
1464 return nil //TODO - complete implementation
1465}
1466
1467// FindFlowById returns the index of the flow in the flows array if present. Otherwise, it returns -1
1468func FindFlowById(flows []*ofp.OfpFlowStats, flow *ofp.OfpFlowStats) int {
1469 for idx, f := range flows {
1470 if flow.Id == f.Id {
1471 return idx
1472 }
1473 }
1474 return -1
1475}
1476
1477// FindFlows returns the index in flows where flow if present. Otherwise, it returns -1
1478func FindFlows(flows []*ofp.OfpFlowStats, flow *ofp.OfpFlowStats) int {
1479 for idx, f := range flows {
Kent Hagermanf9cbe692020-05-05 17:50:26 -04001480 if f.Id == flow.Id {
Scott Baker456b8932019-10-24 10:36:39 -07001481 return idx
1482 }
1483 }
1484 return -1
1485}
1486
Joey Armstrong7f8436c2023-07-09 20:23:27 -04001487// FlowMatch returns true if two flows matches on the following flow attributes:
1488// TableId, Priority, Flags, Cookie, Match
Scott Baker456b8932019-10-24 10:36:39 -07001489func FlowMatch(f1 *ofp.OfpFlowStats, f2 *ofp.OfpFlowStats) bool {
Kent Hagermanf9cbe692020-05-05 17:50:26 -04001490 return f1 != nil && f2 != nil && f1.Id == f2.Id
Scott Baker456b8932019-10-24 10:36:39 -07001491}
1492
Joey Armstrong7f8436c2023-07-09 20:23:27 -04001493// FlowMatchesMod returns True if given flow is "covered" by the wildcard flow_mod, taking into consideration of
1494// both exact matches as well as masks-based match fields if any. Otherwise return False
Scott Baker456b8932019-10-24 10:36:39 -07001495func FlowMatchesMod(flow *ofp.OfpFlowStats, mod *ofp.OfpFlowMod) bool {
1496 if flow == nil || mod == nil {
1497 return false
1498 }
1499 //Check if flow.cookie is covered by mod.cookie and mod.cookie_mask
1500 if (flow.Cookie & mod.CookieMask) != (mod.Cookie & mod.CookieMask) {
1501 return false
1502 }
1503
1504 //Check if flow.table_id is covered by flow_mod.table_id
1505 if mod.TableId != uint32(ofp.OfpTable_OFPTT_ALL) && flow.TableId != mod.TableId {
1506 return false
1507 }
1508
1509 //Check out_port
1510 if (mod.OutPort&0x7fffffff) != uint32(ofp.OfpPortNo_OFPP_ANY) && !FlowHasOutPort(flow, mod.OutPort) {
1511 return false
1512 }
1513
1514 // Check out_group
1515 if (mod.OutGroup&0x7fffffff) != uint32(ofp.OfpGroup_OFPG_ANY) && !FlowHasOutGroup(flow, mod.OutGroup) {
1516 return false
1517 }
1518
1519 //Priority is ignored
1520
1521 //Check match condition
1522 //If the flow_mod match field is empty, that is a special case and indicates the flow entry matches
1523 if (mod.Match == nil) || (mod.Match.OxmFields == nil) || (len(mod.Match.OxmFields) == 0) {
1524 //If we got this far and the match is empty in the flow spec, than the flow matches
1525 return true
1526 } // TODO : implement the flow match analysis
1527 return false
1528
1529}
1530
Joey Armstrong7f8436c2023-07-09 20:23:27 -04001531// FlowHasOutPort returns True if flow has a output command with the given out_port
Scott Baker456b8932019-10-24 10:36:39 -07001532func FlowHasOutPort(flow *ofp.OfpFlowStats, outPort uint32) bool {
1533 if flow == nil {
1534 return false
1535 }
1536 for _, instruction := range flow.Instructions {
1537 if instruction.Type == uint32(ofp.OfpInstructionType_OFPIT_APPLY_ACTIONS) {
1538 if instruction.GetActions() == nil {
1539 return false
1540 }
1541 for _, action := range instruction.GetActions().Actions {
1542 if action.Type == ofp.OfpActionType_OFPAT_OUTPUT {
1543 if (action.GetOutput() != nil) && (action.GetOutput().Port == outPort) {
1544 return true
1545 }
1546 }
1547
1548 }
1549 }
1550 }
1551 return false
1552}
1553
Joey Armstrong7f8436c2023-07-09 20:23:27 -04001554// FlowHasOutGroup return True if flow has a output command with the given out_group
Scott Baker456b8932019-10-24 10:36:39 -07001555func FlowHasOutGroup(flow *ofp.OfpFlowStats, groupID uint32) bool {
1556 if flow == nil {
1557 return false
1558 }
1559 for _, instruction := range flow.Instructions {
1560 if instruction.Type == uint32(ofp.OfpInstructionType_OFPIT_APPLY_ACTIONS) {
1561 if instruction.GetActions() == nil {
1562 return false
1563 }
1564 for _, action := range instruction.GetActions().Actions {
1565 if action.Type == ofp.OfpActionType_OFPAT_GROUP {
1566 if (action.GetGroup() != nil) && (action.GetGroup().GroupId == groupID) {
1567 return true
1568 }
1569 }
1570
1571 }
1572 }
1573 }
1574 return false
1575}
1576
Joey Armstrong7f8436c2023-07-09 20:23:27 -04001577// FindGroup returns index of group if found, else returns -1
Scott Baker456b8932019-10-24 10:36:39 -07001578func FindGroup(groups []*ofp.OfpGroupEntry, groupId uint32) int {
1579 for idx, group := range groups {
1580 if group.Desc.GroupId == groupId {
1581 return idx
1582 }
1583 }
1584 return -1
1585}
1586
1587func FlowsDeleteByGroupId(flows []*ofp.OfpFlowStats, groupId uint32) (bool, []*ofp.OfpFlowStats) {
1588 toKeep := make([]*ofp.OfpFlowStats, 0)
1589
1590 for _, f := range flows {
1591 if !FlowHasOutGroup(f, groupId) {
1592 toKeep = append(toKeep, f)
1593 }
1594 }
1595 return len(toKeep) < len(flows), toKeep
1596}
1597
1598func ToOfpOxmField(from []*ofp.OfpOxmOfbField) []*ofp.OfpOxmField {
1599 matchFields := make([]*ofp.OfpOxmField, 0)
1600 for _, val := range from {
1601 matchFields = append(matchFields, &ofp.OfpOxmField{Field: &ofp.OfpOxmField_OfbField{OfbField: val}})
1602 }
1603 return matchFields
1604}
Esin Karaman20b6de92019-11-05 08:29:16 +00001605
Joey Armstrong7f8436c2023-07-09 20:23:27 -04001606// IsMulticastIp returns true if the ip starts with the byte sequence of 1110;
1607// false otherwise.
Esin Karaman20b6de92019-11-05 08:29:16 +00001608func IsMulticastIp(ip uint32) bool {
1609 return ip>>28 == 14
1610}
1611
Joey Armstrong7f8436c2023-07-09 20:23:27 -04001612// ConvertToMulticastMacInt returns equivalent mac address of the given multicast ip address
Esin Karaman20b6de92019-11-05 08:29:16 +00001613func ConvertToMulticastMacInt(ip uint32) uint64 {
1614 //get last 23 bits of ip address by ip & 00000000011111111111111111111111
1615 theLast23BitsOfIp := ip & 8388607
1616 // perform OR with 0x1005E000000 to build mcast mac address
1617 return 1101088686080 | uint64(theLast23BitsOfIp)
1618}
1619
Joey Armstrong7f8436c2023-07-09 20:23:27 -04001620// ConvertToMulticastMacBytes returns equivalent mac address of the given multicast ip address
Esin Karaman20b6de92019-11-05 08:29:16 +00001621func ConvertToMulticastMacBytes(ip uint32) []byte {
1622 mac := ConvertToMulticastMacInt(ip)
1623 var b bytes.Buffer
1624 // catalyze (48 bits) in binary:111111110000000000000000000000000000000000000000
1625 catalyze := uint64(280375465082880)
1626 //convert each octet to decimal
1627 for i := 0; i < 6; i++ {
1628 if i != 0 {
khenaidoo26721882021-08-11 17:42:52 -04001629 catalyze >>= 8
Esin Karaman20b6de92019-11-05 08:29:16 +00001630 }
1631 octet := mac & catalyze
1632 octetDecimal := octet >> uint8(40-i*8)
1633 b.WriteByte(byte(octetDecimal))
1634 }
1635 return b.Bytes()
1636}
yasin saplid0c5ffd2021-06-17 09:41:04 +00001637
1638func GetMeterIdFromWriteMetadata(ctx context.Context, flow *ofp.OfpFlowStats) uint32 {
1639 /*
1640 Write metadata instruction value (metadata) is 8 bytes:
1641 MS 2 bytes: C Tag
1642 Next 2 bytes: Technology Profile Id
1643 Next 4 bytes: Port number (uni or nni) or MeterId
1644 This is set in the ONOS OltPipeline as a write metadata instruction
1645 */
1646 var meterID uint32 = 0
1647 md := GetMetadataFromWriteMetadataAction(ctx, flow)
1648 logger.Debugw(ctx, "found-metadata-for-egress/uni-port", log.Fields{"metadata": md})
1649 if md != 0 {
1650 meterID = uint32(md & 0xFFFFFFFF)
1651 logger.Debugw(ctx, "found-meterID-in-write-metadata-action", log.Fields{"meterID": meterID})
1652 }
1653 return meterID
1654}
1655
1656func SetMeterIdToFlow(flow *ofp.OfpFlowStats, meterId uint32) {
1657 if flow != nil {
1658 for _, instruction := range flow.Instructions {
1659 if instruction.Type == uint32(METER_ACTION) {
1660 if meterInst := instruction.GetMeter(); meterInst != nil {
1661 meterInst.MeterId = meterId
1662 }
1663 }
1664 }
1665 }
1666}