blob: cc0c595916f6790eaeef566ad9752e828271e1f2 [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"
Andrea Campanella30342622020-03-05 20:48:26 +010021 "encoding/binary"
David K. Bainbridge157bdab2020-01-16 14:38:05 -080022 "encoding/json"
Jonathan Hart828908c2020-04-15 14:23:45 -070023 ofp "github.com/opencord/goloxi/of13"
David K. Bainbridgeaea73cd2020-01-27 10:44:50 -080024 "github.com/opencord/voltha-lib-go/v3/pkg/log"
25 "github.com/opencord/voltha-protos/v3/go/openflow_13"
26 "github.com/opencord/voltha-protos/v3/go/voltha"
Jonathan Hart60c5d772020-03-30 18:28:40 -070027 "net"
David K. Bainbridge157bdab2020-01-16 14:38:05 -080028)
29
30var oxmMap = map[string]int32{
Don Newton7fe70f72020-02-21 13:54:11 -050031 "in_port": 0,
32 "in_phy_port": 1,
33 "metadata": 2,
34 "eth_dst": 3,
35 "eth_src": 4,
36 "eth_type": 5,
37 "vlan_vid": 6,
38 "vlan_pcp": 7,
39 "ip_dscp": 8,
40 "ip_ecn": 9,
41 "ip_proto": 10,
42 "ipv4_src": 11,
43 "ipv4_dst": 12,
44 "tcp_src": 13,
45 "tcp_dst": 14,
46 "udp_src": 15,
47 "udp_dst": 16,
48 "sctp_src": 17,
49 "sctp_dst": 18,
50 "icmpv4_type": 19,
51 "icmpv4_code": 20,
52 "arp_op": 21,
53 "arp_spa": 22,
54 "arp_tpa": 23,
55 "arp_sha": 24,
56 "arp_tha": 25,
57 "ipv6_src": 26,
58 "ipv6_dst": 27,
59 "ipv6_flabel": 28,
60 "icmpv6_type": 29,
61 "icmpv6_code": 30,
62 "ipv6_nd_target": 31,
63 "ipv6_nd_sll": 32,
64 "ipv6_nd_tll": 33,
65 "mpls_label": 34,
66 "mpls_tc": 35,
67 "mpls_bos": 36,
68 "pbb_isid": 37,
69 "tunnel_id": 38,
70 "ipv6_exthdr": 39,
71 "vlan_vid_masked": 200, //made up
David K. Bainbridge157bdab2020-01-16 14:38:05 -080072}
73
Jonathan Hart4b110f62020-03-13 17:36:19 -070074func (ofc *OFConnection) handleFlowAdd(flowAdd *ofp.FlowAdd) {
David K. Bainbridge157bdab2020-01-16 14:38:05 -080075 if logger.V(log.DebugLevel) {
76 js, _ := json.Marshal(flowAdd)
77 logger.Debugw("handleFlowAdd called",
78 log.Fields{
79 "device-id": ofc.DeviceID,
80 "params": js})
81 }
82
David Bainbridgef8ce7d22020-04-08 12:49:41 -070083 volthaClient := ofc.VolthaClient.Get()
84 if volthaClient == nil {
David K. Bainbridge9cb404e2020-01-28 14:32:29 -080085 logger.Errorw("no-voltha-connection",
86 log.Fields{"device-id": ofc.DeviceID})
87 return
88 }
89
David K. Bainbridge157bdab2020-01-16 14:38:05 -080090 // Construct the match
91 var oxmList []*voltha.OfpOxmField
92 for _, oxmField := range flowAdd.Match.GetOxmList() {
93 name := oxmMap[oxmField.GetOXMName()]
94 val := oxmField.GetOXMValue()
95 field := voltha.OfpOxmOfbField{Type: voltha.OxmOfbFieldTypes(name)}
96 ofpOxmField := voltha.OfpOxmField{
97 OxmClass: ofp.OFPXMCOpenflowBasic,
98 Field: &openflow_13.OfpOxmField_OfbField{OfbField: &field},
99 }
100 switch voltha.OxmOfbFieldTypes(name) {
101 case voltha.OxmOfbFieldTypes_OFPXMT_OFB_IN_PORT:
102 field.Value = &voltha.OfpOxmOfbField_Port{
103 Port: uint32(val.(ofp.Port)),
104 }
105 case voltha.OxmOfbFieldTypes_OFPXMT_OFB_IN_PHY_PORT:
106 field.Value = &voltha.OfpOxmOfbField_PhysicalPort{
107 PhysicalPort: val.(uint32),
108 }
109 case voltha.OxmOfbFieldTypes_OFPXMT_OFB_METADATA:
110 field.Value = &voltha.OfpOxmOfbField_TableMetadata{
111 TableMetadata: val.(uint64),
112 }
113 case voltha.OxmOfbFieldTypes_OFPXMT_OFB_ETH_TYPE:
114 field.Value = &voltha.OfpOxmOfbField_EthType{
115 EthType: uint32(val.(ofp.EthernetType)),
116 }
117 case voltha.OxmOfbFieldTypes_OFPXMT_OFB_IP_PROTO:
118 field.Value = &voltha.OfpOxmOfbField_IpProto{
119 IpProto: uint32(val.(ofp.IpPrototype)),
120 }
Jonathan Hart60c5d772020-03-30 18:28:40 -0700121 case voltha.OxmOfbFieldTypes_OFPXMT_OFB_IPV4_DST:
122 field.Value = &voltha.OfpOxmOfbField_Ipv4Dst{
123 Ipv4Dst: binary.BigEndian.Uint32(val.(net.IP)),
124 }
Gamze Abaka3e2b2ce2020-05-09 10:21:40 +0000125 case voltha.OxmOfbFieldTypes_OFPXMT_OFB_ETH_DST:
126 field.Value = &voltha.OfpOxmOfbField_EthDst{
127 EthDst: val.(net.HardwareAddr),
128 }
David K. Bainbridge157bdab2020-01-16 14:38:05 -0800129 case voltha.OxmOfbFieldTypes_OFPXMT_OFB_UDP_SRC:
130 field.Value = &voltha.OfpOxmOfbField_UdpSrc{
131 UdpSrc: uint32(val.(uint16)),
132 }
133 case voltha.OxmOfbFieldTypes_OFPXMT_OFB_UDP_DST:
134 field.Value = &voltha.OfpOxmOfbField_UdpDst{
135 UdpDst: uint32(val.(uint16)),
136 }
137 case voltha.OxmOfbFieldTypes_OFPXMT_OFB_VLAN_VID:
138 field.Value = &voltha.OfpOxmOfbField_VlanVid{
139 VlanVid: uint32((val.(uint16) & 0xfff) | 0x1000),
140 }
Gamze Abaka3e2b2ce2020-05-09 10:21:40 +0000141 case voltha.OxmOfbFieldTypes_OFPXMT_OFB_VLAN_PCP:
142 field.Value = &voltha.OfpOxmOfbField_VlanPcp{
143 VlanPcp: uint32(val.(uint8)),
144 }
Don Newton7fe70f72020-02-21 13:54:11 -0500145 case 200: // voltha-protos doesn't actually have a type for vlan_mask
146 field = voltha.OfpOxmOfbField{Type: voltha.OxmOfbFieldTypes(oxmMap["vlan_vid"])}
147 field.HasMask = true
148 ofpOxmField = voltha.OfpOxmField{
149 OxmClass: ofp.OFPXMCOpenflowBasic,
150 Field: &openflow_13.OfpOxmField_OfbField{OfbField: &field},
151 }
152 field.Value = &voltha.OfpOxmOfbField_VlanVid{
153 VlanVid: uint32(val.(uint16)),
154 }
155 vidMask := val.(uint16)
156 field.Mask = &voltha.OfpOxmOfbField_VlanVidMask{
157 VlanVidMask: uint32(vidMask),
158 }
David K. Bainbridge157bdab2020-01-16 14:38:05 -0800159 }
160 oxmList = append(oxmList, &ofpOxmField)
161 }
162
163 // Construct the instructions
164 var instructions []*voltha.OfpInstruction
165 for _, ofpInstruction := range flowAdd.GetInstructions() {
166 instructionType := ofpInstruction.GetType()
167 instruction := voltha.OfpInstruction{Type: uint32(instructionType)}
168 switch instructionType {
169 case ofp.OFPITGotoTable:
170 instruction.Data = &openflow_13.OfpInstruction_GotoTable{
171 GotoTable: &openflow_13.OfpInstructionGotoTable{
172 TableId: uint32(ofpInstruction.(ofp.IInstructionGotoTable).GetTableId()),
173 },
174 }
175 case ofp.OFPITWriteMetadata:
176 instruction.Data = &openflow_13.OfpInstruction_WriteMetadata{
177 WriteMetadata: &openflow_13.OfpInstructionWriteMetadata{
178 Metadata: ofpInstruction.(ofp.IInstructionWriteMetadata).GetMetadata(),
179 MetadataMask: ofpInstruction.(ofp.IInstructionWriteMetadata).GetMetadataMask(),
180 },
181 }
182 case ofp.OFPITWriteActions:
183 var ofpActions []*openflow_13.OfpAction
184 for _, action := range ofpInstruction.(ofp.IInstructionWriteActions).GetActions() {
185 ofpActions = append(ofpActions, extractAction(action))
186 }
187 instruction.Data = &openflow_13.OfpInstruction_Actions{
188 Actions: &openflow_13.OfpInstructionActions{
189 Actions: ofpActions,
190 },
191 }
192 case ofp.OFPITApplyActions:
193 var ofpActions []*openflow_13.OfpAction
194 for _, action := range ofpInstruction.(ofp.IInstructionApplyActions).GetActions() {
195 ofpActions = append(ofpActions, extractAction(action))
196 }
197 instruction.Data = &openflow_13.OfpInstruction_Actions{
198 Actions: &openflow_13.OfpInstructionActions{
199 Actions: ofpActions,
200 },
201 }
202 case ofp.OFPITMeter:
203 instruction.Data = &openflow_13.OfpInstruction_Meter{
204 Meter: &openflow_13.OfpInstructionMeter{
205 MeterId: ofpInstruction.(ofp.IInstructionMeter).GetMeterId(),
206 },
207 }
208 }
209 instructions = append(instructions, &instruction)
210 }
211
212 // Construct the request
213 flowUpdate := openflow_13.FlowTableUpdate{
214 Id: ofc.DeviceID,
215 FlowMod: &voltha.OfpFlowMod{
216 Cookie: flowAdd.Cookie,
217 CookieMask: flowAdd.CookieMask,
218 TableId: uint32(flowAdd.TableId),
219 Command: voltha.OfpFlowModCommand_OFPFC_ADD,
220 IdleTimeout: uint32(flowAdd.IdleTimeout),
221 HardTimeout: uint32(flowAdd.HardTimeout),
222 Priority: uint32(flowAdd.Priority),
223 BufferId: flowAdd.BufferId,
224 OutPort: uint32(flowAdd.OutPort),
225 OutGroup: uint32(flowAdd.OutGroup),
226 Flags: uint32(flowAdd.Flags),
227 Match: &voltha.OfpMatch{
228 Type: voltha.OfpMatchType(flowAdd.Match.GetType()),
229 OxmFields: oxmList,
230 },
231
232 Instructions: instructions,
233 },
234 }
235 if logger.V(log.DebugLevel) {
236 flowUpdateJs, _ := json.Marshal(flowUpdate)
Andrea Campanella91c4e4e2020-03-05 16:52:06 +0100237 logger.Debugf("FlowAdd being sent to Voltha",
David K. Bainbridge157bdab2020-01-16 14:38:05 -0800238 log.Fields{
239 "device-id": ofc.DeviceID,
Don Newton7fe70f72020-02-21 13:54:11 -0500240 "flow-mod-object": flowUpdate,
David K. Bainbridge157bdab2020-01-16 14:38:05 -0800241 "flow-mod-request": flowUpdateJs})
242 }
David Bainbridgef8ce7d22020-04-08 12:49:41 -0700243 if _, err := volthaClient.UpdateLogicalDeviceFlowTable(context.Background(), &flowUpdate); err != nil {
Andrea Campanella91c4e4e2020-03-05 16:52:06 +0100244 logger.Errorw("Error calling FlowAdd ",
David K. Bainbridge157bdab2020-01-16 14:38:05 -0800245 log.Fields{
246 "device-id": ofc.DeviceID,
247 "error": err})
Andrea Campanella30342622020-03-05 20:48:26 +0100248 // Report failure to controller
249 message := ofp.NewFlowModFailedErrorMsg()
250 message.SetXid(flowAdd.Xid)
251 message.SetCode(ofp.OFPFMFCBadCommand)
252 //OF 1.3
253 message.SetVersion(4)
254 bs := make([]byte, 2)
255 //OF 1.3
256 bs[0] = byte(4)
257 //Flow Mod
258 bs[1] = byte(14)
259 //Length of the message
260 length := make([]byte, 2)
261 binary.BigEndian.PutUint16(length, 56)
262 bs = append(bs, length...)
263 empty := []byte{0, 0, 0, 0}
264 bs = append(bs, empty...)
265 //Cookie of the Flow
266 cookie := make([]byte, 52)
267 binary.BigEndian.PutUint64(cookie, flowAdd.Cookie)
268 bs = append(bs, cookie...)
269 message.SetData(bs)
Andrea Campanella30342622020-03-05 20:48:26 +0100270 err := ofc.SendMessage(message)
271 if err != nil {
272 logger.Errorw("Error reporting failure of FlowUpdate to controller",
273 log.Fields{
274 "device-id": ofc.DeviceID,
275 "error": err})
276 }
David K. Bainbridge157bdab2020-01-16 14:38:05 -0800277 }
278}
279
Jonathan Hart4b110f62020-03-13 17:36:19 -0700280func (ofc *OFConnection) handleFlowMod(flowMod *ofp.FlowMod) {
David K. Bainbridge157bdab2020-01-16 14:38:05 -0800281 if logger.V(log.DebugLevel) {
282 js, _ := json.Marshal(flowMod)
Andrea Campanella91c4e4e2020-03-05 16:52:06 +0100283 logger.Debugw("handleFlowMod called",
David K. Bainbridge157bdab2020-01-16 14:38:05 -0800284 log.Fields{
285 "device-id": ofc.DeviceID,
286 "flow-mod": js})
287 }
288 logger.Errorw("handleFlowMod not implemented",
289 log.Fields{"device-id": ofc.DeviceID})
290}
291
Jonathan Hart4b110f62020-03-13 17:36:19 -0700292func (ofc *OFConnection) handleFlowModStrict(flowModStrict *ofp.FlowModifyStrict) {
David K. Bainbridge157bdab2020-01-16 14:38:05 -0800293 if logger.V(log.DebugLevel) {
294 js, _ := json.Marshal(flowModStrict)
295 logger.Debugw("handleFlowModStrict called",
296 log.Fields{
297 "device-id": ofc.DeviceID,
298 "flow-mod-strict": js})
299 }
300 logger.Error("handleFlowModStrict not implemented",
301 log.Fields{"device-id": ofc.DeviceID})
302}
303
Jonathan Hart4b110f62020-03-13 17:36:19 -0700304func (ofc *OFConnection) handleFlowDelete(flowDelete *ofp.FlowDelete) {
David K. Bainbridge157bdab2020-01-16 14:38:05 -0800305 if logger.V(log.DebugLevel) {
306 js, _ := json.Marshal(flowDelete)
307 logger.Debugw("handleFlowDelete called",
308 log.Fields{
309 "device-id": ofc.DeviceID,
310 "flow-delete": js})
311 }
312 logger.Error("handleFlowDelete not implemented",
313 log.Fields{"device-id": ofc.DeviceID})
314
315}
316
Jonathan Hart4b110f62020-03-13 17:36:19 -0700317func (ofc *OFConnection) handleFlowDeleteStrict(flowDeleteStrict *ofp.FlowDeleteStrict) {
David K. Bainbridge157bdab2020-01-16 14:38:05 -0800318 if logger.V(log.DebugLevel) {
319 js, _ := json.Marshal(flowDeleteStrict)
Andrea Campanella91c4e4e2020-03-05 16:52:06 +0100320 logger.Debugw("handleFlowDeleteStrict called",
David K. Bainbridge157bdab2020-01-16 14:38:05 -0800321 log.Fields{
322 "device-id": ofc.DeviceID,
323 "flow-delete-strict": js})
324 }
325
David Bainbridgef8ce7d22020-04-08 12:49:41 -0700326 volthaClient := ofc.VolthaClient.Get()
327 if volthaClient == nil {
David K. Bainbridge9cb404e2020-01-28 14:32:29 -0800328 logger.Errorw("no-voltha-connection",
329 log.Fields{"device-id": ofc.DeviceID})
330 return
331 }
332
David K. Bainbridge157bdab2020-01-16 14:38:05 -0800333 // Construct match
334 var oxmList []*voltha.OfpOxmField
335 for _, oxmField := range flowDeleteStrict.Match.GetOxmList() {
336 name := oxmMap[oxmField.GetOXMName()]
337 val := oxmField.GetOXMValue()
338 var ofpOxmField voltha.OfpOxmField
339 ofpOxmField.OxmClass = ofp.OFPXMCOpenflowBasic
340 var field voltha.OfpOxmOfbField
341 field.Type = voltha.OxmOfbFieldTypes(name)
342
343 var x openflow_13.OfpOxmField_OfbField
344 x.OfbField = &field
345 ofpOxmField.Field = &x
346
347 switch voltha.OxmOfbFieldTypes(name) {
348 case voltha.OxmOfbFieldTypes_OFPXMT_OFB_IN_PORT:
349 field.Value = &voltha.OfpOxmOfbField_Port{
350 Port: uint32(val.(ofp.Port)),
351 }
352 case voltha.OxmOfbFieldTypes_OFPXMT_OFB_IN_PHY_PORT:
353 field.Value = &voltha.OfpOxmOfbField_PhysicalPort{
354 PhysicalPort: val.(uint32),
355 }
356 case voltha.OxmOfbFieldTypes_OFPXMT_OFB_METADATA:
357 field.Value = &voltha.OfpOxmOfbField_TableMetadata{
358 TableMetadata: val.(uint64),
359 }
360 case voltha.OxmOfbFieldTypes_OFPXMT_OFB_ETH_TYPE:
361 field.Value = &voltha.OfpOxmOfbField_EthType{
362 EthType: uint32(val.(ofp.EthernetType)),
363 }
364 case voltha.OxmOfbFieldTypes_OFPXMT_OFB_IP_PROTO:
365 field.Value = &voltha.OfpOxmOfbField_IpProto{
366 IpProto: uint32(val.(ofp.IpPrototype)),
367 }
Jonathan Hart60c5d772020-03-30 18:28:40 -0700368 case voltha.OxmOfbFieldTypes_OFPXMT_OFB_IPV4_DST:
369 field.Value = &voltha.OfpOxmOfbField_Ipv4Dst{
370 Ipv4Dst: binary.BigEndian.Uint32(val.(net.IP)),
371 }
David K. Bainbridge157bdab2020-01-16 14:38:05 -0800372 case voltha.OxmOfbFieldTypes_OFPXMT_OFB_UDP_SRC:
373 field.Value = &voltha.OfpOxmOfbField_UdpSrc{
374 UdpSrc: uint32(val.(uint16)),
375 }
376 case voltha.OxmOfbFieldTypes_OFPXMT_OFB_UDP_DST:
377 field.Value = &voltha.OfpOxmOfbField_UdpDst{
378 UdpDst: uint32(val.(uint16)),
379 }
380 case voltha.OxmOfbFieldTypes_OFPXMT_OFB_VLAN_VID:
381 field.Value = &voltha.OfpOxmOfbField_VlanVid{
382 VlanVid: uint32(val.(uint16)),
383 }
Don Newton7fe70f72020-02-21 13:54:11 -0500384 case 200: // voltha-protos doesn't actually have a type for vlan_mask
385 field = voltha.OfpOxmOfbField{Type: voltha.OxmOfbFieldTypes(oxmMap["vlan_vid"])}
386 field.HasMask = true
387 ofpOxmField = voltha.OfpOxmField{
388 OxmClass: ofp.OFPXMCOpenflowBasic,
389 Field: &openflow_13.OfpOxmField_OfbField{OfbField: &field},
390 }
391 field.Value = &voltha.OfpOxmOfbField_VlanVid{
392 VlanVid: uint32(val.(uint16)),
393 }
394 vidMask := val.(uint16)
395 field.Mask = &voltha.OfpOxmOfbField_VlanVidMask{
396 VlanVidMask: uint32(vidMask),
397 }
David K. Bainbridge157bdab2020-01-16 14:38:05 -0800398 }
Don Newton7fe70f72020-02-21 13:54:11 -0500399
David K. Bainbridge157bdab2020-01-16 14:38:05 -0800400 oxmList = append(oxmList, &ofpOxmField)
401 }
402
Matteo Scandolo322c3082020-06-17 14:21:26 -0700403 responseRequired := false
404
405 if flowDeleteStrict.GetFlags() == ofp.OFPFFSendFlowRem {
406 responseRequired = true
407 }
408
David K. Bainbridge157bdab2020-01-16 14:38:05 -0800409 // Construct request
410 flowUpdate := openflow_13.FlowTableUpdate{
411 Id: ofc.DeviceID,
412 FlowMod: &voltha.OfpFlowMod{
413 Cookie: flowDeleteStrict.Cookie,
414 CookieMask: flowDeleteStrict.CookieMask,
415 TableId: uint32(flowDeleteStrict.TableId),
416 Command: voltha.OfpFlowModCommand_OFPFC_DELETE_STRICT,
417 IdleTimeout: uint32(flowDeleteStrict.IdleTimeout),
418 HardTimeout: uint32(flowDeleteStrict.HardTimeout),
419 Priority: uint32(flowDeleteStrict.Priority),
420 BufferId: flowDeleteStrict.BufferId,
421 OutPort: uint32(flowDeleteStrict.OutPort),
422 OutGroup: uint32(flowDeleteStrict.OutGroup),
423 Flags: uint32(flowDeleteStrict.Flags),
424 Match: &voltha.OfpMatch{
425 Type: voltha.OfpMatchType(flowDeleteStrict.Match.GetType()),
426 OxmFields: oxmList,
427 },
428 },
429 }
430
431 if logger.V(log.DebugLevel) {
432 flowUpdateJs, _ := json.Marshal(flowUpdate)
Andrea Campanella91c4e4e2020-03-05 16:52:06 +0100433 logger.Debugf("FlowDeleteStrict being sent to Voltha",
David K. Bainbridge157bdab2020-01-16 14:38:05 -0800434 log.Fields{
435 "device-id": ofc.DeviceID,
436 "flow-update": flowUpdateJs})
437 }
David Bainbridgef8ce7d22020-04-08 12:49:41 -0700438 if _, err := volthaClient.UpdateLogicalDeviceFlowTable(context.Background(), &flowUpdate); err != nil {
Andrea Campanella91c4e4e2020-03-05 16:52:06 +0100439 logger.Errorw("Error calling FlowDelete ",
David K. Bainbridge157bdab2020-01-16 14:38:05 -0800440 log.Fields{
441 "device-id": ofc.DeviceID,
442 "error": err})
Matteo Scandolo322c3082020-06-17 14:21:26 -0700443 return
David K. Bainbridge157bdab2020-01-16 14:38:05 -0800444 }
Matteo Scandolo322c3082020-06-17 14:21:26 -0700445
446 if responseRequired {
447 response := ofp.NewFlowRemoved()
448
449 response.Cookie = flowDeleteStrict.Cookie
450 response.Priority = flowDeleteStrict.Priority
451 response.Reason = ofp.OFPRRDelete
452 response.Match = flowDeleteStrict.Match
453 response.IdleTimeout = flowDeleteStrict.IdleTimeout
454 response.HardTimeout = flowDeleteStrict.HardTimeout
455 response.Xid = flowDeleteStrict.Xid
456
457 err := ofc.SendMessage(response)
458 if err != nil {
459 logger.Errorw("Error sending FlowRemoved to ONOS",
460 log.Fields{
461 "device-id": ofc.DeviceID,
462 "error": err})
463 }
464 }
465
David K. Bainbridge157bdab2020-01-16 14:38:05 -0800466}