blob: da4fc1de192e62be674955f260814ea507dec373 [file] [log] [blame]
David K. Bainbridge157bdab2020-01-16 14:38:05 -08001/*
2 Copyright 2020 the original author or authors.
3
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*/
16
17package openflow
18
19import (
20 "context"
21 "encoding/json"
22 ofp "github.com/donNewtonAlpha/goloxi/of13"
David K. Bainbridgeaea73cd2020-01-27 10:44:50 -080023 "github.com/opencord/voltha-lib-go/v3/pkg/log"
24 "github.com/opencord/voltha-protos/v3/go/openflow_13"
25 "github.com/opencord/voltha-protos/v3/go/voltha"
David K. Bainbridge157bdab2020-01-16 14:38:05 -080026)
27
28var oxmMap = map[string]int32{
Don Newton7fe70f72020-02-21 13:54:11 -050029 "in_port": 0,
30 "in_phy_port": 1,
31 "metadata": 2,
32 "eth_dst": 3,
33 "eth_src": 4,
34 "eth_type": 5,
35 "vlan_vid": 6,
36 "vlan_pcp": 7,
37 "ip_dscp": 8,
38 "ip_ecn": 9,
39 "ip_proto": 10,
40 "ipv4_src": 11,
41 "ipv4_dst": 12,
42 "tcp_src": 13,
43 "tcp_dst": 14,
44 "udp_src": 15,
45 "udp_dst": 16,
46 "sctp_src": 17,
47 "sctp_dst": 18,
48 "icmpv4_type": 19,
49 "icmpv4_code": 20,
50 "arp_op": 21,
51 "arp_spa": 22,
52 "arp_tpa": 23,
53 "arp_sha": 24,
54 "arp_tha": 25,
55 "ipv6_src": 26,
56 "ipv6_dst": 27,
57 "ipv6_flabel": 28,
58 "icmpv6_type": 29,
59 "icmpv6_code": 30,
60 "ipv6_nd_target": 31,
61 "ipv6_nd_sll": 32,
62 "ipv6_nd_tll": 33,
63 "mpls_label": 34,
64 "mpls_tc": 35,
65 "mpls_bos": 36,
66 "pbb_isid": 37,
67 "tunnel_id": 38,
68 "ipv6_exthdr": 39,
69 "vlan_vid_masked": 200, //made up
David K. Bainbridge157bdab2020-01-16 14:38:05 -080070}
71
72func (ofc *OFClient) handleFlowAdd(flowAdd *ofp.FlowAdd) {
73 if logger.V(log.DebugLevel) {
74 js, _ := json.Marshal(flowAdd)
75 logger.Debugw("handleFlowAdd called",
76 log.Fields{
77 "device-id": ofc.DeviceID,
78 "params": js})
79 }
80
David K. Bainbridge9cb404e2020-01-28 14:32:29 -080081 if ofc.VolthaClient == nil {
82 logger.Errorw("no-voltha-connection",
83 log.Fields{"device-id": ofc.DeviceID})
84 return
85 }
86
David K. Bainbridge157bdab2020-01-16 14:38:05 -080087 // Construct the match
88 var oxmList []*voltha.OfpOxmField
89 for _, oxmField := range flowAdd.Match.GetOxmList() {
90 name := oxmMap[oxmField.GetOXMName()]
91 val := oxmField.GetOXMValue()
92 field := voltha.OfpOxmOfbField{Type: voltha.OxmOfbFieldTypes(name)}
93 ofpOxmField := voltha.OfpOxmField{
94 OxmClass: ofp.OFPXMCOpenflowBasic,
95 Field: &openflow_13.OfpOxmField_OfbField{OfbField: &field},
96 }
97 switch voltha.OxmOfbFieldTypes(name) {
98 case voltha.OxmOfbFieldTypes_OFPXMT_OFB_IN_PORT:
99 field.Value = &voltha.OfpOxmOfbField_Port{
100 Port: uint32(val.(ofp.Port)),
101 }
102 case voltha.OxmOfbFieldTypes_OFPXMT_OFB_IN_PHY_PORT:
103 field.Value = &voltha.OfpOxmOfbField_PhysicalPort{
104 PhysicalPort: val.(uint32),
105 }
106 case voltha.OxmOfbFieldTypes_OFPXMT_OFB_METADATA:
107 field.Value = &voltha.OfpOxmOfbField_TableMetadata{
108 TableMetadata: val.(uint64),
109 }
110 case voltha.OxmOfbFieldTypes_OFPXMT_OFB_ETH_TYPE:
111 field.Value = &voltha.OfpOxmOfbField_EthType{
112 EthType: uint32(val.(ofp.EthernetType)),
113 }
114 case voltha.OxmOfbFieldTypes_OFPXMT_OFB_IP_PROTO:
115 field.Value = &voltha.OfpOxmOfbField_IpProto{
116 IpProto: uint32(val.(ofp.IpPrototype)),
117 }
118 case voltha.OxmOfbFieldTypes_OFPXMT_OFB_UDP_SRC:
119 field.Value = &voltha.OfpOxmOfbField_UdpSrc{
120 UdpSrc: uint32(val.(uint16)),
121 }
122 case voltha.OxmOfbFieldTypes_OFPXMT_OFB_UDP_DST:
123 field.Value = &voltha.OfpOxmOfbField_UdpDst{
124 UdpDst: uint32(val.(uint16)),
125 }
126 case voltha.OxmOfbFieldTypes_OFPXMT_OFB_VLAN_VID:
127 field.Value = &voltha.OfpOxmOfbField_VlanVid{
128 VlanVid: uint32((val.(uint16) & 0xfff) | 0x1000),
129 }
Don Newton7fe70f72020-02-21 13:54:11 -0500130 case 200: // voltha-protos doesn't actually have a type for vlan_mask
131 field = voltha.OfpOxmOfbField{Type: voltha.OxmOfbFieldTypes(oxmMap["vlan_vid"])}
132 field.HasMask = true
133 ofpOxmField = voltha.OfpOxmField{
134 OxmClass: ofp.OFPXMCOpenflowBasic,
135 Field: &openflow_13.OfpOxmField_OfbField{OfbField: &field},
136 }
137 field.Value = &voltha.OfpOxmOfbField_VlanVid{
138 VlanVid: uint32(val.(uint16)),
139 }
140 vidMask := val.(uint16)
141 field.Mask = &voltha.OfpOxmOfbField_VlanVidMask{
142 VlanVidMask: uint32(vidMask),
143 }
David K. Bainbridge157bdab2020-01-16 14:38:05 -0800144 }
145 oxmList = append(oxmList, &ofpOxmField)
146 }
147
148 // Construct the instructions
149 var instructions []*voltha.OfpInstruction
150 for _, ofpInstruction := range flowAdd.GetInstructions() {
151 instructionType := ofpInstruction.GetType()
152 instruction := voltha.OfpInstruction{Type: uint32(instructionType)}
153 switch instructionType {
154 case ofp.OFPITGotoTable:
155 instruction.Data = &openflow_13.OfpInstruction_GotoTable{
156 GotoTable: &openflow_13.OfpInstructionGotoTable{
157 TableId: uint32(ofpInstruction.(ofp.IInstructionGotoTable).GetTableId()),
158 },
159 }
160 case ofp.OFPITWriteMetadata:
161 instruction.Data = &openflow_13.OfpInstruction_WriteMetadata{
162 WriteMetadata: &openflow_13.OfpInstructionWriteMetadata{
163 Metadata: ofpInstruction.(ofp.IInstructionWriteMetadata).GetMetadata(),
164 MetadataMask: ofpInstruction.(ofp.IInstructionWriteMetadata).GetMetadataMask(),
165 },
166 }
167 case ofp.OFPITWriteActions:
168 var ofpActions []*openflow_13.OfpAction
169 for _, action := range ofpInstruction.(ofp.IInstructionWriteActions).GetActions() {
170 ofpActions = append(ofpActions, extractAction(action))
171 }
172 instruction.Data = &openflow_13.OfpInstruction_Actions{
173 Actions: &openflow_13.OfpInstructionActions{
174 Actions: ofpActions,
175 },
176 }
177 case ofp.OFPITApplyActions:
178 var ofpActions []*openflow_13.OfpAction
179 for _, action := range ofpInstruction.(ofp.IInstructionApplyActions).GetActions() {
180 ofpActions = append(ofpActions, extractAction(action))
181 }
182 instruction.Data = &openflow_13.OfpInstruction_Actions{
183 Actions: &openflow_13.OfpInstructionActions{
184 Actions: ofpActions,
185 },
186 }
187 case ofp.OFPITMeter:
188 instruction.Data = &openflow_13.OfpInstruction_Meter{
189 Meter: &openflow_13.OfpInstructionMeter{
190 MeterId: ofpInstruction.(ofp.IInstructionMeter).GetMeterId(),
191 },
192 }
193 }
194 instructions = append(instructions, &instruction)
195 }
196
197 // Construct the request
198 flowUpdate := openflow_13.FlowTableUpdate{
199 Id: ofc.DeviceID,
200 FlowMod: &voltha.OfpFlowMod{
201 Cookie: flowAdd.Cookie,
202 CookieMask: flowAdd.CookieMask,
203 TableId: uint32(flowAdd.TableId),
204 Command: voltha.OfpFlowModCommand_OFPFC_ADD,
205 IdleTimeout: uint32(flowAdd.IdleTimeout),
206 HardTimeout: uint32(flowAdd.HardTimeout),
207 Priority: uint32(flowAdd.Priority),
208 BufferId: flowAdd.BufferId,
209 OutPort: uint32(flowAdd.OutPort),
210 OutGroup: uint32(flowAdd.OutGroup),
211 Flags: uint32(flowAdd.Flags),
212 Match: &voltha.OfpMatch{
213 Type: voltha.OfpMatchType(flowAdd.Match.GetType()),
214 OxmFields: oxmList,
215 },
216
217 Instructions: instructions,
218 },
219 }
220 if logger.V(log.DebugLevel) {
221 flowUpdateJs, _ := json.Marshal(flowUpdate)
222 logger.Debugf("FlowUpdate being sent to Voltha",
223 log.Fields{
224 "device-id": ofc.DeviceID,
Don Newton7fe70f72020-02-21 13:54:11 -0500225 "flow-mod-object": flowUpdate,
David K. Bainbridge157bdab2020-01-16 14:38:05 -0800226 "flow-mod-request": flowUpdateJs})
227 }
228 if _, err := ofc.VolthaClient.UpdateLogicalDeviceFlowTable(context.Background(), &flowUpdate); err != nil {
229 logger.Errorw("Error calling FlowUpdate ",
230 log.Fields{
231 "device-id": ofc.DeviceID,
232 "error": err})
233 }
234}
235
236func (ofc *OFClient) handleFlowMod(flowMod *ofp.FlowMod) {
237 if logger.V(log.DebugLevel) {
238 js, _ := json.Marshal(flowMod)
239 logger.Debugw("handleMod called",
240 log.Fields{
241 "device-id": ofc.DeviceID,
242 "flow-mod": js})
243 }
244 logger.Errorw("handleFlowMod not implemented",
245 log.Fields{"device-id": ofc.DeviceID})
246}
247
248func (ofc *OFClient) handleFlowModStrict(flowModStrict *ofp.FlowModifyStrict) {
249 if logger.V(log.DebugLevel) {
250 js, _ := json.Marshal(flowModStrict)
251 logger.Debugw("handleFlowModStrict called",
252 log.Fields{
253 "device-id": ofc.DeviceID,
254 "flow-mod-strict": js})
255 }
256 logger.Error("handleFlowModStrict not implemented",
257 log.Fields{"device-id": ofc.DeviceID})
258}
259
260func (ofc *OFClient) handleFlowDelete(flowDelete *ofp.FlowDelete) {
261 if logger.V(log.DebugLevel) {
262 js, _ := json.Marshal(flowDelete)
263 logger.Debugw("handleFlowDelete called",
264 log.Fields{
265 "device-id": ofc.DeviceID,
266 "flow-delete": js})
267 }
268 logger.Error("handleFlowDelete not implemented",
269 log.Fields{"device-id": ofc.DeviceID})
270
271}
272
273func (ofc *OFClient) handleFlowDeleteStrict(flowDeleteStrict *ofp.FlowDeleteStrict) {
274 if logger.V(log.DebugLevel) {
275 js, _ := json.Marshal(flowDeleteStrict)
276 logger.Debugw("handleFlowAdd called",
277 log.Fields{
278 "device-id": ofc.DeviceID,
279 "flow-delete-strict": js})
280 }
281
David K. Bainbridge9cb404e2020-01-28 14:32:29 -0800282 if ofc.VolthaClient == nil {
283 logger.Errorw("no-voltha-connection",
284 log.Fields{"device-id": ofc.DeviceID})
285 return
286 }
287
David K. Bainbridge157bdab2020-01-16 14:38:05 -0800288 // Construct match
289 var oxmList []*voltha.OfpOxmField
290 for _, oxmField := range flowDeleteStrict.Match.GetOxmList() {
291 name := oxmMap[oxmField.GetOXMName()]
292 val := oxmField.GetOXMValue()
293 var ofpOxmField voltha.OfpOxmField
294 ofpOxmField.OxmClass = ofp.OFPXMCOpenflowBasic
295 var field voltha.OfpOxmOfbField
296 field.Type = voltha.OxmOfbFieldTypes(name)
297
298 var x openflow_13.OfpOxmField_OfbField
299 x.OfbField = &field
300 ofpOxmField.Field = &x
301
302 switch voltha.OxmOfbFieldTypes(name) {
303 case voltha.OxmOfbFieldTypes_OFPXMT_OFB_IN_PORT:
304 field.Value = &voltha.OfpOxmOfbField_Port{
305 Port: uint32(val.(ofp.Port)),
306 }
307 case voltha.OxmOfbFieldTypes_OFPXMT_OFB_IN_PHY_PORT:
308 field.Value = &voltha.OfpOxmOfbField_PhysicalPort{
309 PhysicalPort: val.(uint32),
310 }
311 case voltha.OxmOfbFieldTypes_OFPXMT_OFB_METADATA:
312 field.Value = &voltha.OfpOxmOfbField_TableMetadata{
313 TableMetadata: val.(uint64),
314 }
315 case voltha.OxmOfbFieldTypes_OFPXMT_OFB_ETH_TYPE:
316 field.Value = &voltha.OfpOxmOfbField_EthType{
317 EthType: uint32(val.(ofp.EthernetType)),
318 }
319 case voltha.OxmOfbFieldTypes_OFPXMT_OFB_IP_PROTO:
320 field.Value = &voltha.OfpOxmOfbField_IpProto{
321 IpProto: uint32(val.(ofp.IpPrototype)),
322 }
323 case voltha.OxmOfbFieldTypes_OFPXMT_OFB_UDP_SRC:
324 field.Value = &voltha.OfpOxmOfbField_UdpSrc{
325 UdpSrc: uint32(val.(uint16)),
326 }
327 case voltha.OxmOfbFieldTypes_OFPXMT_OFB_UDP_DST:
328 field.Value = &voltha.OfpOxmOfbField_UdpDst{
329 UdpDst: uint32(val.(uint16)),
330 }
331 case voltha.OxmOfbFieldTypes_OFPXMT_OFB_VLAN_VID:
332 field.Value = &voltha.OfpOxmOfbField_VlanVid{
333 VlanVid: uint32(val.(uint16)),
334 }
Don Newton7fe70f72020-02-21 13:54:11 -0500335 case 200: // voltha-protos doesn't actually have a type for vlan_mask
336 field = voltha.OfpOxmOfbField{Type: voltha.OxmOfbFieldTypes(oxmMap["vlan_vid"])}
337 field.HasMask = true
338 ofpOxmField = voltha.OfpOxmField{
339 OxmClass: ofp.OFPXMCOpenflowBasic,
340 Field: &openflow_13.OfpOxmField_OfbField{OfbField: &field},
341 }
342 field.Value = &voltha.OfpOxmOfbField_VlanVid{
343 VlanVid: uint32(val.(uint16)),
344 }
345 vidMask := val.(uint16)
346 field.Mask = &voltha.OfpOxmOfbField_VlanVidMask{
347 VlanVidMask: uint32(vidMask),
348 }
David K. Bainbridge157bdab2020-01-16 14:38:05 -0800349 }
Don Newton7fe70f72020-02-21 13:54:11 -0500350
David K. Bainbridge157bdab2020-01-16 14:38:05 -0800351 oxmList = append(oxmList, &ofpOxmField)
352 }
353
354 // Construct request
355 flowUpdate := openflow_13.FlowTableUpdate{
356 Id: ofc.DeviceID,
357 FlowMod: &voltha.OfpFlowMod{
358 Cookie: flowDeleteStrict.Cookie,
359 CookieMask: flowDeleteStrict.CookieMask,
360 TableId: uint32(flowDeleteStrict.TableId),
361 Command: voltha.OfpFlowModCommand_OFPFC_DELETE_STRICT,
362 IdleTimeout: uint32(flowDeleteStrict.IdleTimeout),
363 HardTimeout: uint32(flowDeleteStrict.HardTimeout),
364 Priority: uint32(flowDeleteStrict.Priority),
365 BufferId: flowDeleteStrict.BufferId,
366 OutPort: uint32(flowDeleteStrict.OutPort),
367 OutGroup: uint32(flowDeleteStrict.OutGroup),
368 Flags: uint32(flowDeleteStrict.Flags),
369 Match: &voltha.OfpMatch{
370 Type: voltha.OfpMatchType(flowDeleteStrict.Match.GetType()),
371 OxmFields: oxmList,
372 },
373 },
374 }
375
376 if logger.V(log.DebugLevel) {
377 flowUpdateJs, _ := json.Marshal(flowUpdate)
378 logger.Debugf("FlowUpdate being sent to Voltha",
379 log.Fields{
380 "device-id": ofc.DeviceID,
381 "flow-update": flowUpdateJs})
382 }
383 if _, err := ofc.VolthaClient.UpdateLogicalDeviceFlowTable(context.Background(), &flowUpdate); err != nil {
384 logger.Errorw("Error calling FlowUpdate ",
385 log.Fields{
386 "device-id": ofc.DeviceID,
387 "error": err})
388 }
389}