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