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