blob: 5424c121a31aeea10b573e896b48662bd69e99a0 [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"
David Bainbridgef8ce7d22020-04-08 12:49:41 -070023 "unsafe"
24
David K. Bainbridge157bdab2020-01-16 14:38:05 -080025 ofp "github.com/donNewtonAlpha/goloxi/of13"
David K. Bainbridgeaea73cd2020-01-27 10:44:50 -080026 "github.com/opencord/voltha-lib-go/v3/pkg/log"
27 "github.com/opencord/voltha-protos/v3/go/openflow_13"
28 "github.com/opencord/voltha-protos/v3/go/voltha"
David K. Bainbridge157bdab2020-01-16 14:38:05 -080029)
30
31var oxmMap = map[string]int32{
Don Newton7fe70f72020-02-21 13:54:11 -050032 "in_port": 0,
33 "in_phy_port": 1,
34 "metadata": 2,
35 "eth_dst": 3,
36 "eth_src": 4,
37 "eth_type": 5,
38 "vlan_vid": 6,
39 "vlan_pcp": 7,
40 "ip_dscp": 8,
41 "ip_ecn": 9,
42 "ip_proto": 10,
43 "ipv4_src": 11,
44 "ipv4_dst": 12,
45 "tcp_src": 13,
46 "tcp_dst": 14,
47 "udp_src": 15,
48 "udp_dst": 16,
49 "sctp_src": 17,
50 "sctp_dst": 18,
51 "icmpv4_type": 19,
52 "icmpv4_code": 20,
53 "arp_op": 21,
54 "arp_spa": 22,
55 "arp_tpa": 23,
56 "arp_sha": 24,
57 "arp_tha": 25,
58 "ipv6_src": 26,
59 "ipv6_dst": 27,
60 "ipv6_flabel": 28,
61 "icmpv6_type": 29,
62 "icmpv6_code": 30,
63 "ipv6_nd_target": 31,
64 "ipv6_nd_sll": 32,
65 "ipv6_nd_tll": 33,
66 "mpls_label": 34,
67 "mpls_tc": 35,
68 "mpls_bos": 36,
69 "pbb_isid": 37,
70 "tunnel_id": 38,
71 "ipv6_exthdr": 39,
72 "vlan_vid_masked": 200, //made up
David K. Bainbridge157bdab2020-01-16 14:38:05 -080073}
74
Jonathan Hart4b110f62020-03-13 17:36:19 -070075func (ofc *OFConnection) handleFlowAdd(flowAdd *ofp.FlowAdd) {
David K. Bainbridge157bdab2020-01-16 14:38:05 -080076 if logger.V(log.DebugLevel) {
77 js, _ := json.Marshal(flowAdd)
78 logger.Debugw("handleFlowAdd called",
79 log.Fields{
80 "device-id": ofc.DeviceID,
81 "params": js})
82 }
83
David Bainbridgef8ce7d22020-04-08 12:49:41 -070084 volthaClient := ofc.VolthaClient.Get()
85 if volthaClient == nil {
David K. Bainbridge9cb404e2020-01-28 14:32:29 -080086 logger.Errorw("no-voltha-connection",
87 log.Fields{"device-id": ofc.DeviceID})
88 return
89 }
90
David K. Bainbridge157bdab2020-01-16 14:38:05 -080091 // Construct the match
92 var oxmList []*voltha.OfpOxmField
93 for _, oxmField := range flowAdd.Match.GetOxmList() {
94 name := oxmMap[oxmField.GetOXMName()]
95 val := oxmField.GetOXMValue()
96 field := voltha.OfpOxmOfbField{Type: voltha.OxmOfbFieldTypes(name)}
97 ofpOxmField := voltha.OfpOxmField{
98 OxmClass: ofp.OFPXMCOpenflowBasic,
99 Field: &openflow_13.OfpOxmField_OfbField{OfbField: &field},
100 }
101 switch voltha.OxmOfbFieldTypes(name) {
102 case voltha.OxmOfbFieldTypes_OFPXMT_OFB_IN_PORT:
103 field.Value = &voltha.OfpOxmOfbField_Port{
104 Port: uint32(val.(ofp.Port)),
105 }
106 case voltha.OxmOfbFieldTypes_OFPXMT_OFB_IN_PHY_PORT:
107 field.Value = &voltha.OfpOxmOfbField_PhysicalPort{
108 PhysicalPort: val.(uint32),
109 }
110 case voltha.OxmOfbFieldTypes_OFPXMT_OFB_METADATA:
111 field.Value = &voltha.OfpOxmOfbField_TableMetadata{
112 TableMetadata: val.(uint64),
113 }
114 case voltha.OxmOfbFieldTypes_OFPXMT_OFB_ETH_TYPE:
115 field.Value = &voltha.OfpOxmOfbField_EthType{
116 EthType: uint32(val.(ofp.EthernetType)),
117 }
118 case voltha.OxmOfbFieldTypes_OFPXMT_OFB_IP_PROTO:
119 field.Value = &voltha.OfpOxmOfbField_IpProto{
120 IpProto: uint32(val.(ofp.IpPrototype)),
121 }
122 case voltha.OxmOfbFieldTypes_OFPXMT_OFB_UDP_SRC:
123 field.Value = &voltha.OfpOxmOfbField_UdpSrc{
124 UdpSrc: uint32(val.(uint16)),
125 }
126 case voltha.OxmOfbFieldTypes_OFPXMT_OFB_UDP_DST:
127 field.Value = &voltha.OfpOxmOfbField_UdpDst{
128 UdpDst: uint32(val.(uint16)),
129 }
130 case voltha.OxmOfbFieldTypes_OFPXMT_OFB_VLAN_VID:
131 field.Value = &voltha.OfpOxmOfbField_VlanVid{
132 VlanVid: uint32((val.(uint16) & 0xfff) | 0x1000),
133 }
Don Newton7fe70f72020-02-21 13:54:11 -0500134 case 200: // voltha-protos doesn't actually have a type for vlan_mask
135 field = voltha.OfpOxmOfbField{Type: voltha.OxmOfbFieldTypes(oxmMap["vlan_vid"])}
136 field.HasMask = true
137 ofpOxmField = voltha.OfpOxmField{
138 OxmClass: ofp.OFPXMCOpenflowBasic,
139 Field: &openflow_13.OfpOxmField_OfbField{OfbField: &field},
140 }
141 field.Value = &voltha.OfpOxmOfbField_VlanVid{
142 VlanVid: uint32(val.(uint16)),
143 }
144 vidMask := val.(uint16)
145 field.Mask = &voltha.OfpOxmOfbField_VlanVidMask{
146 VlanVidMask: uint32(vidMask),
147 }
David K. Bainbridge157bdab2020-01-16 14:38:05 -0800148 }
149 oxmList = append(oxmList, &ofpOxmField)
150 }
151
152 // Construct the instructions
153 var instructions []*voltha.OfpInstruction
154 for _, ofpInstruction := range flowAdd.GetInstructions() {
155 instructionType := ofpInstruction.GetType()
156 instruction := voltha.OfpInstruction{Type: uint32(instructionType)}
157 switch instructionType {
158 case ofp.OFPITGotoTable:
159 instruction.Data = &openflow_13.OfpInstruction_GotoTable{
160 GotoTable: &openflow_13.OfpInstructionGotoTable{
161 TableId: uint32(ofpInstruction.(ofp.IInstructionGotoTable).GetTableId()),
162 },
163 }
164 case ofp.OFPITWriteMetadata:
165 instruction.Data = &openflow_13.OfpInstruction_WriteMetadata{
166 WriteMetadata: &openflow_13.OfpInstructionWriteMetadata{
167 Metadata: ofpInstruction.(ofp.IInstructionWriteMetadata).GetMetadata(),
168 MetadataMask: ofpInstruction.(ofp.IInstructionWriteMetadata).GetMetadataMask(),
169 },
170 }
171 case ofp.OFPITWriteActions:
172 var ofpActions []*openflow_13.OfpAction
173 for _, action := range ofpInstruction.(ofp.IInstructionWriteActions).GetActions() {
174 ofpActions = append(ofpActions, extractAction(action))
175 }
176 instruction.Data = &openflow_13.OfpInstruction_Actions{
177 Actions: &openflow_13.OfpInstructionActions{
178 Actions: ofpActions,
179 },
180 }
181 case ofp.OFPITApplyActions:
182 var ofpActions []*openflow_13.OfpAction
183 for _, action := range ofpInstruction.(ofp.IInstructionApplyActions).GetActions() {
184 ofpActions = append(ofpActions, extractAction(action))
185 }
186 instruction.Data = &openflow_13.OfpInstruction_Actions{
187 Actions: &openflow_13.OfpInstructionActions{
188 Actions: ofpActions,
189 },
190 }
191 case ofp.OFPITMeter:
192 instruction.Data = &openflow_13.OfpInstruction_Meter{
193 Meter: &openflow_13.OfpInstructionMeter{
194 MeterId: ofpInstruction.(ofp.IInstructionMeter).GetMeterId(),
195 },
196 }
197 }
198 instructions = append(instructions, &instruction)
199 }
200
201 // Construct the request
202 flowUpdate := openflow_13.FlowTableUpdate{
203 Id: ofc.DeviceID,
204 FlowMod: &voltha.OfpFlowMod{
205 Cookie: flowAdd.Cookie,
206 CookieMask: flowAdd.CookieMask,
207 TableId: uint32(flowAdd.TableId),
208 Command: voltha.OfpFlowModCommand_OFPFC_ADD,
209 IdleTimeout: uint32(flowAdd.IdleTimeout),
210 HardTimeout: uint32(flowAdd.HardTimeout),
211 Priority: uint32(flowAdd.Priority),
212 BufferId: flowAdd.BufferId,
213 OutPort: uint32(flowAdd.OutPort),
214 OutGroup: uint32(flowAdd.OutGroup),
215 Flags: uint32(flowAdd.Flags),
216 Match: &voltha.OfpMatch{
217 Type: voltha.OfpMatchType(flowAdd.Match.GetType()),
218 OxmFields: oxmList,
219 },
220
221 Instructions: instructions,
222 },
223 }
224 if logger.V(log.DebugLevel) {
225 flowUpdateJs, _ := json.Marshal(flowUpdate)
Andrea Campanella91c4e4e2020-03-05 16:52:06 +0100226 logger.Debugf("FlowAdd being sent to Voltha",
David K. Bainbridge157bdab2020-01-16 14:38:05 -0800227 log.Fields{
228 "device-id": ofc.DeviceID,
Don Newton7fe70f72020-02-21 13:54:11 -0500229 "flow-mod-object": flowUpdate,
David K. Bainbridge157bdab2020-01-16 14:38:05 -0800230 "flow-mod-request": flowUpdateJs})
231 }
David Bainbridgef8ce7d22020-04-08 12:49:41 -0700232 if _, err := volthaClient.UpdateLogicalDeviceFlowTable(context.Background(), &flowUpdate); err != nil {
Andrea Campanella91c4e4e2020-03-05 16:52:06 +0100233 logger.Errorw("Error calling FlowAdd ",
David K. Bainbridge157bdab2020-01-16 14:38:05 -0800234 log.Fields{
235 "device-id": ofc.DeviceID,
236 "error": err})
Andrea Campanella30342622020-03-05 20:48:26 +0100237 // Report failure to controller
238 message := ofp.NewFlowModFailedErrorMsg()
239 message.SetXid(flowAdd.Xid)
240 message.SetCode(ofp.OFPFMFCBadCommand)
241 //OF 1.3
242 message.SetVersion(4)
243 bs := make([]byte, 2)
244 //OF 1.3
245 bs[0] = byte(4)
246 //Flow Mod
247 bs[1] = byte(14)
248 //Length of the message
249 length := make([]byte, 2)
250 binary.BigEndian.PutUint16(length, 56)
251 bs = append(bs, length...)
252 empty := []byte{0, 0, 0, 0}
253 bs = append(bs, empty...)
254 //Cookie of the Flow
255 cookie := make([]byte, 52)
256 binary.BigEndian.PutUint64(cookie, flowAdd.Cookie)
257 bs = append(bs, cookie...)
258 message.SetData(bs)
259 message.Length = uint16(unsafe.Sizeof(*message))
260 err := ofc.SendMessage(message)
261 if err != nil {
262 logger.Errorw("Error reporting failure of FlowUpdate to controller",
263 log.Fields{
264 "device-id": ofc.DeviceID,
265 "error": err})
266 }
David K. Bainbridge157bdab2020-01-16 14:38:05 -0800267 }
268}
269
Jonathan Hart4b110f62020-03-13 17:36:19 -0700270func (ofc *OFConnection) handleFlowMod(flowMod *ofp.FlowMod) {
David K. Bainbridge157bdab2020-01-16 14:38:05 -0800271 if logger.V(log.DebugLevel) {
272 js, _ := json.Marshal(flowMod)
Andrea Campanella91c4e4e2020-03-05 16:52:06 +0100273 logger.Debugw("handleFlowMod called",
David K. Bainbridge157bdab2020-01-16 14:38:05 -0800274 log.Fields{
275 "device-id": ofc.DeviceID,
276 "flow-mod": js})
277 }
278 logger.Errorw("handleFlowMod not implemented",
279 log.Fields{"device-id": ofc.DeviceID})
280}
281
Jonathan Hart4b110f62020-03-13 17:36:19 -0700282func (ofc *OFConnection) handleFlowModStrict(flowModStrict *ofp.FlowModifyStrict) {
David K. Bainbridge157bdab2020-01-16 14:38:05 -0800283 if logger.V(log.DebugLevel) {
284 js, _ := json.Marshal(flowModStrict)
285 logger.Debugw("handleFlowModStrict called",
286 log.Fields{
287 "device-id": ofc.DeviceID,
288 "flow-mod-strict": js})
289 }
290 logger.Error("handleFlowModStrict not implemented",
291 log.Fields{"device-id": ofc.DeviceID})
292}
293
Jonathan Hart4b110f62020-03-13 17:36:19 -0700294func (ofc *OFConnection) handleFlowDelete(flowDelete *ofp.FlowDelete) {
David K. Bainbridge157bdab2020-01-16 14:38:05 -0800295 if logger.V(log.DebugLevel) {
296 js, _ := json.Marshal(flowDelete)
297 logger.Debugw("handleFlowDelete called",
298 log.Fields{
299 "device-id": ofc.DeviceID,
300 "flow-delete": js})
301 }
302 logger.Error("handleFlowDelete not implemented",
303 log.Fields{"device-id": ofc.DeviceID})
304
305}
306
Jonathan Hart4b110f62020-03-13 17:36:19 -0700307func (ofc *OFConnection) handleFlowDeleteStrict(flowDeleteStrict *ofp.FlowDeleteStrict) {
David K. Bainbridge157bdab2020-01-16 14:38:05 -0800308 if logger.V(log.DebugLevel) {
309 js, _ := json.Marshal(flowDeleteStrict)
Andrea Campanella91c4e4e2020-03-05 16:52:06 +0100310 logger.Debugw("handleFlowDeleteStrict called",
David K. Bainbridge157bdab2020-01-16 14:38:05 -0800311 log.Fields{
312 "device-id": ofc.DeviceID,
313 "flow-delete-strict": js})
314 }
315
David Bainbridgef8ce7d22020-04-08 12:49:41 -0700316 volthaClient := ofc.VolthaClient.Get()
317 if volthaClient == nil {
David K. Bainbridge9cb404e2020-01-28 14:32:29 -0800318 logger.Errorw("no-voltha-connection",
319 log.Fields{"device-id": ofc.DeviceID})
320 return
321 }
322
David K. Bainbridge157bdab2020-01-16 14:38:05 -0800323 // Construct match
324 var oxmList []*voltha.OfpOxmField
325 for _, oxmField := range flowDeleteStrict.Match.GetOxmList() {
326 name := oxmMap[oxmField.GetOXMName()]
327 val := oxmField.GetOXMValue()
328 var ofpOxmField voltha.OfpOxmField
329 ofpOxmField.OxmClass = ofp.OFPXMCOpenflowBasic
330 var field voltha.OfpOxmOfbField
331 field.Type = voltha.OxmOfbFieldTypes(name)
332
333 var x openflow_13.OfpOxmField_OfbField
334 x.OfbField = &field
335 ofpOxmField.Field = &x
336
337 switch voltha.OxmOfbFieldTypes(name) {
338 case voltha.OxmOfbFieldTypes_OFPXMT_OFB_IN_PORT:
339 field.Value = &voltha.OfpOxmOfbField_Port{
340 Port: uint32(val.(ofp.Port)),
341 }
342 case voltha.OxmOfbFieldTypes_OFPXMT_OFB_IN_PHY_PORT:
343 field.Value = &voltha.OfpOxmOfbField_PhysicalPort{
344 PhysicalPort: val.(uint32),
345 }
346 case voltha.OxmOfbFieldTypes_OFPXMT_OFB_METADATA:
347 field.Value = &voltha.OfpOxmOfbField_TableMetadata{
348 TableMetadata: val.(uint64),
349 }
350 case voltha.OxmOfbFieldTypes_OFPXMT_OFB_ETH_TYPE:
351 field.Value = &voltha.OfpOxmOfbField_EthType{
352 EthType: uint32(val.(ofp.EthernetType)),
353 }
354 case voltha.OxmOfbFieldTypes_OFPXMT_OFB_IP_PROTO:
355 field.Value = &voltha.OfpOxmOfbField_IpProto{
356 IpProto: uint32(val.(ofp.IpPrototype)),
357 }
358 case voltha.OxmOfbFieldTypes_OFPXMT_OFB_UDP_SRC:
359 field.Value = &voltha.OfpOxmOfbField_UdpSrc{
360 UdpSrc: uint32(val.(uint16)),
361 }
362 case voltha.OxmOfbFieldTypes_OFPXMT_OFB_UDP_DST:
363 field.Value = &voltha.OfpOxmOfbField_UdpDst{
364 UdpDst: uint32(val.(uint16)),
365 }
366 case voltha.OxmOfbFieldTypes_OFPXMT_OFB_VLAN_VID:
367 field.Value = &voltha.OfpOxmOfbField_VlanVid{
368 VlanVid: uint32(val.(uint16)),
369 }
Don Newton7fe70f72020-02-21 13:54:11 -0500370 case 200: // voltha-protos doesn't actually have a type for vlan_mask
371 field = voltha.OfpOxmOfbField{Type: voltha.OxmOfbFieldTypes(oxmMap["vlan_vid"])}
372 field.HasMask = true
373 ofpOxmField = voltha.OfpOxmField{
374 OxmClass: ofp.OFPXMCOpenflowBasic,
375 Field: &openflow_13.OfpOxmField_OfbField{OfbField: &field},
376 }
377 field.Value = &voltha.OfpOxmOfbField_VlanVid{
378 VlanVid: uint32(val.(uint16)),
379 }
380 vidMask := val.(uint16)
381 field.Mask = &voltha.OfpOxmOfbField_VlanVidMask{
382 VlanVidMask: uint32(vidMask),
383 }
David K. Bainbridge157bdab2020-01-16 14:38:05 -0800384 }
Don Newton7fe70f72020-02-21 13:54:11 -0500385
David K. Bainbridge157bdab2020-01-16 14:38:05 -0800386 oxmList = append(oxmList, &ofpOxmField)
387 }
388
389 // Construct request
390 flowUpdate := openflow_13.FlowTableUpdate{
391 Id: ofc.DeviceID,
392 FlowMod: &voltha.OfpFlowMod{
393 Cookie: flowDeleteStrict.Cookie,
394 CookieMask: flowDeleteStrict.CookieMask,
395 TableId: uint32(flowDeleteStrict.TableId),
396 Command: voltha.OfpFlowModCommand_OFPFC_DELETE_STRICT,
397 IdleTimeout: uint32(flowDeleteStrict.IdleTimeout),
398 HardTimeout: uint32(flowDeleteStrict.HardTimeout),
399 Priority: uint32(flowDeleteStrict.Priority),
400 BufferId: flowDeleteStrict.BufferId,
401 OutPort: uint32(flowDeleteStrict.OutPort),
402 OutGroup: uint32(flowDeleteStrict.OutGroup),
403 Flags: uint32(flowDeleteStrict.Flags),
404 Match: &voltha.OfpMatch{
405 Type: voltha.OfpMatchType(flowDeleteStrict.Match.GetType()),
406 OxmFields: oxmList,
407 },
408 },
409 }
410
411 if logger.V(log.DebugLevel) {
412 flowUpdateJs, _ := json.Marshal(flowUpdate)
Andrea Campanella91c4e4e2020-03-05 16:52:06 +0100413 logger.Debugf("FlowDeleteStrict being sent to Voltha",
David K. Bainbridge157bdab2020-01-16 14:38:05 -0800414 log.Fields{
415 "device-id": ofc.DeviceID,
416 "flow-update": flowUpdateJs})
417 }
David Bainbridgef8ce7d22020-04-08 12:49:41 -0700418 if _, err := volthaClient.UpdateLogicalDeviceFlowTable(context.Background(), &flowUpdate); err != nil {
Andrea Campanella91c4e4e2020-03-05 16:52:06 +0100419 logger.Errorw("Error calling FlowDelete ",
David K. Bainbridge157bdab2020-01-16 14:38:05 -0800420 log.Fields{
421 "device-id": ofc.DeviceID,
422 "error": err})
423 }
424}