blob: 08c0b982ff848d0d48563c2d36c73800e52823ce [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"
Jonathan Hart60c5d772020-03-30 18:28:40 -070029 "net"
David K. Bainbridge157bdab2020-01-16 14:38:05 -080030)
31
32var oxmMap = map[string]int32{
Don Newton7fe70f72020-02-21 13:54:11 -050033 "in_port": 0,
34 "in_phy_port": 1,
35 "metadata": 2,
36 "eth_dst": 3,
37 "eth_src": 4,
38 "eth_type": 5,
39 "vlan_vid": 6,
40 "vlan_pcp": 7,
41 "ip_dscp": 8,
42 "ip_ecn": 9,
43 "ip_proto": 10,
44 "ipv4_src": 11,
45 "ipv4_dst": 12,
46 "tcp_src": 13,
47 "tcp_dst": 14,
48 "udp_src": 15,
49 "udp_dst": 16,
50 "sctp_src": 17,
51 "sctp_dst": 18,
52 "icmpv4_type": 19,
53 "icmpv4_code": 20,
54 "arp_op": 21,
55 "arp_spa": 22,
56 "arp_tpa": 23,
57 "arp_sha": 24,
58 "arp_tha": 25,
59 "ipv6_src": 26,
60 "ipv6_dst": 27,
61 "ipv6_flabel": 28,
62 "icmpv6_type": 29,
63 "icmpv6_code": 30,
64 "ipv6_nd_target": 31,
65 "ipv6_nd_sll": 32,
66 "ipv6_nd_tll": 33,
67 "mpls_label": 34,
68 "mpls_tc": 35,
69 "mpls_bos": 36,
70 "pbb_isid": 37,
71 "tunnel_id": 38,
72 "ipv6_exthdr": 39,
73 "vlan_vid_masked": 200, //made up
David K. Bainbridge157bdab2020-01-16 14:38:05 -080074}
75
Jonathan Hart4b110f62020-03-13 17:36:19 -070076func (ofc *OFConnection) handleFlowAdd(flowAdd *ofp.FlowAdd) {
David K. Bainbridge157bdab2020-01-16 14:38:05 -080077 if logger.V(log.DebugLevel) {
78 js, _ := json.Marshal(flowAdd)
79 logger.Debugw("handleFlowAdd called",
80 log.Fields{
81 "device-id": ofc.DeviceID,
82 "params": js})
83 }
84
David Bainbridgef8ce7d22020-04-08 12:49:41 -070085 volthaClient := ofc.VolthaClient.Get()
86 if volthaClient == nil {
David K. Bainbridge9cb404e2020-01-28 14:32:29 -080087 logger.Errorw("no-voltha-connection",
88 log.Fields{"device-id": ofc.DeviceID})
89 return
90 }
91
David K. Bainbridge157bdab2020-01-16 14:38:05 -080092 // Construct the match
93 var oxmList []*voltha.OfpOxmField
94 for _, oxmField := range flowAdd.Match.GetOxmList() {
95 name := oxmMap[oxmField.GetOXMName()]
96 val := oxmField.GetOXMValue()
97 field := voltha.OfpOxmOfbField{Type: voltha.OxmOfbFieldTypes(name)}
98 ofpOxmField := voltha.OfpOxmField{
99 OxmClass: ofp.OFPXMCOpenflowBasic,
100 Field: &openflow_13.OfpOxmField_OfbField{OfbField: &field},
101 }
102 switch voltha.OxmOfbFieldTypes(name) {
103 case voltha.OxmOfbFieldTypes_OFPXMT_OFB_IN_PORT:
104 field.Value = &voltha.OfpOxmOfbField_Port{
105 Port: uint32(val.(ofp.Port)),
106 }
107 case voltha.OxmOfbFieldTypes_OFPXMT_OFB_IN_PHY_PORT:
108 field.Value = &voltha.OfpOxmOfbField_PhysicalPort{
109 PhysicalPort: val.(uint32),
110 }
111 case voltha.OxmOfbFieldTypes_OFPXMT_OFB_METADATA:
112 field.Value = &voltha.OfpOxmOfbField_TableMetadata{
113 TableMetadata: val.(uint64),
114 }
115 case voltha.OxmOfbFieldTypes_OFPXMT_OFB_ETH_TYPE:
116 field.Value = &voltha.OfpOxmOfbField_EthType{
117 EthType: uint32(val.(ofp.EthernetType)),
118 }
119 case voltha.OxmOfbFieldTypes_OFPXMT_OFB_IP_PROTO:
120 field.Value = &voltha.OfpOxmOfbField_IpProto{
121 IpProto: uint32(val.(ofp.IpPrototype)),
122 }
Jonathan Hart60c5d772020-03-30 18:28:40 -0700123 case voltha.OxmOfbFieldTypes_OFPXMT_OFB_IPV4_DST:
124 field.Value = &voltha.OfpOxmOfbField_Ipv4Dst{
125 Ipv4Dst: binary.BigEndian.Uint32(val.(net.IP)),
126 }
David K. Bainbridge157bdab2020-01-16 14:38:05 -0800127 case voltha.OxmOfbFieldTypes_OFPXMT_OFB_UDP_SRC:
128 field.Value = &voltha.OfpOxmOfbField_UdpSrc{
129 UdpSrc: uint32(val.(uint16)),
130 }
131 case voltha.OxmOfbFieldTypes_OFPXMT_OFB_UDP_DST:
132 field.Value = &voltha.OfpOxmOfbField_UdpDst{
133 UdpDst: uint32(val.(uint16)),
134 }
135 case voltha.OxmOfbFieldTypes_OFPXMT_OFB_VLAN_VID:
136 field.Value = &voltha.OfpOxmOfbField_VlanVid{
137 VlanVid: uint32((val.(uint16) & 0xfff) | 0x1000),
138 }
Don Newton7fe70f72020-02-21 13:54:11 -0500139 case 200: // voltha-protos doesn't actually have a type for vlan_mask
140 field = voltha.OfpOxmOfbField{Type: voltha.OxmOfbFieldTypes(oxmMap["vlan_vid"])}
141 field.HasMask = true
142 ofpOxmField = voltha.OfpOxmField{
143 OxmClass: ofp.OFPXMCOpenflowBasic,
144 Field: &openflow_13.OfpOxmField_OfbField{OfbField: &field},
145 }
146 field.Value = &voltha.OfpOxmOfbField_VlanVid{
147 VlanVid: uint32(val.(uint16)),
148 }
149 vidMask := val.(uint16)
150 field.Mask = &voltha.OfpOxmOfbField_VlanVidMask{
151 VlanVidMask: uint32(vidMask),
152 }
David K. Bainbridge157bdab2020-01-16 14:38:05 -0800153 }
154 oxmList = append(oxmList, &ofpOxmField)
155 }
156
157 // Construct the instructions
158 var instructions []*voltha.OfpInstruction
159 for _, ofpInstruction := range flowAdd.GetInstructions() {
160 instructionType := ofpInstruction.GetType()
161 instruction := voltha.OfpInstruction{Type: uint32(instructionType)}
162 switch instructionType {
163 case ofp.OFPITGotoTable:
164 instruction.Data = &openflow_13.OfpInstruction_GotoTable{
165 GotoTable: &openflow_13.OfpInstructionGotoTable{
166 TableId: uint32(ofpInstruction.(ofp.IInstructionGotoTable).GetTableId()),
167 },
168 }
169 case ofp.OFPITWriteMetadata:
170 instruction.Data = &openflow_13.OfpInstruction_WriteMetadata{
171 WriteMetadata: &openflow_13.OfpInstructionWriteMetadata{
172 Metadata: ofpInstruction.(ofp.IInstructionWriteMetadata).GetMetadata(),
173 MetadataMask: ofpInstruction.(ofp.IInstructionWriteMetadata).GetMetadataMask(),
174 },
175 }
176 case ofp.OFPITWriteActions:
177 var ofpActions []*openflow_13.OfpAction
178 for _, action := range ofpInstruction.(ofp.IInstructionWriteActions).GetActions() {
179 ofpActions = append(ofpActions, extractAction(action))
180 }
181 instruction.Data = &openflow_13.OfpInstruction_Actions{
182 Actions: &openflow_13.OfpInstructionActions{
183 Actions: ofpActions,
184 },
185 }
186 case ofp.OFPITApplyActions:
187 var ofpActions []*openflow_13.OfpAction
188 for _, action := range ofpInstruction.(ofp.IInstructionApplyActions).GetActions() {
189 ofpActions = append(ofpActions, extractAction(action))
190 }
191 instruction.Data = &openflow_13.OfpInstruction_Actions{
192 Actions: &openflow_13.OfpInstructionActions{
193 Actions: ofpActions,
194 },
195 }
196 case ofp.OFPITMeter:
197 instruction.Data = &openflow_13.OfpInstruction_Meter{
198 Meter: &openflow_13.OfpInstructionMeter{
199 MeterId: ofpInstruction.(ofp.IInstructionMeter).GetMeterId(),
200 },
201 }
202 }
203 instructions = append(instructions, &instruction)
204 }
205
206 // Construct the request
207 flowUpdate := openflow_13.FlowTableUpdate{
208 Id: ofc.DeviceID,
209 FlowMod: &voltha.OfpFlowMod{
210 Cookie: flowAdd.Cookie,
211 CookieMask: flowAdd.CookieMask,
212 TableId: uint32(flowAdd.TableId),
213 Command: voltha.OfpFlowModCommand_OFPFC_ADD,
214 IdleTimeout: uint32(flowAdd.IdleTimeout),
215 HardTimeout: uint32(flowAdd.HardTimeout),
216 Priority: uint32(flowAdd.Priority),
217 BufferId: flowAdd.BufferId,
218 OutPort: uint32(flowAdd.OutPort),
219 OutGroup: uint32(flowAdd.OutGroup),
220 Flags: uint32(flowAdd.Flags),
221 Match: &voltha.OfpMatch{
222 Type: voltha.OfpMatchType(flowAdd.Match.GetType()),
223 OxmFields: oxmList,
224 },
225
226 Instructions: instructions,
227 },
228 }
229 if logger.V(log.DebugLevel) {
230 flowUpdateJs, _ := json.Marshal(flowUpdate)
Andrea Campanella91c4e4e2020-03-05 16:52:06 +0100231 logger.Debugf("FlowAdd being sent to Voltha",
David K. Bainbridge157bdab2020-01-16 14:38:05 -0800232 log.Fields{
233 "device-id": ofc.DeviceID,
Don Newton7fe70f72020-02-21 13:54:11 -0500234 "flow-mod-object": flowUpdate,
David K. Bainbridge157bdab2020-01-16 14:38:05 -0800235 "flow-mod-request": flowUpdateJs})
236 }
David Bainbridgef8ce7d22020-04-08 12:49:41 -0700237 if _, err := volthaClient.UpdateLogicalDeviceFlowTable(context.Background(), &flowUpdate); err != nil {
Andrea Campanella91c4e4e2020-03-05 16:52:06 +0100238 logger.Errorw("Error calling FlowAdd ",
David K. Bainbridge157bdab2020-01-16 14:38:05 -0800239 log.Fields{
240 "device-id": ofc.DeviceID,
241 "error": err})
Andrea Campanella30342622020-03-05 20:48:26 +0100242 // Report failure to controller
243 message := ofp.NewFlowModFailedErrorMsg()
244 message.SetXid(flowAdd.Xid)
245 message.SetCode(ofp.OFPFMFCBadCommand)
246 //OF 1.3
247 message.SetVersion(4)
248 bs := make([]byte, 2)
249 //OF 1.3
250 bs[0] = byte(4)
251 //Flow Mod
252 bs[1] = byte(14)
253 //Length of the message
254 length := make([]byte, 2)
255 binary.BigEndian.PutUint16(length, 56)
256 bs = append(bs, length...)
257 empty := []byte{0, 0, 0, 0}
258 bs = append(bs, empty...)
259 //Cookie of the Flow
260 cookie := make([]byte, 52)
261 binary.BigEndian.PutUint64(cookie, flowAdd.Cookie)
262 bs = append(bs, cookie...)
263 message.SetData(bs)
264 message.Length = uint16(unsafe.Sizeof(*message))
265 err := ofc.SendMessage(message)
266 if err != nil {
267 logger.Errorw("Error reporting failure of FlowUpdate to controller",
268 log.Fields{
269 "device-id": ofc.DeviceID,
270 "error": err})
271 }
David K. Bainbridge157bdab2020-01-16 14:38:05 -0800272 }
273}
274
Jonathan Hart4b110f62020-03-13 17:36:19 -0700275func (ofc *OFConnection) handleFlowMod(flowMod *ofp.FlowMod) {
David K. Bainbridge157bdab2020-01-16 14:38:05 -0800276 if logger.V(log.DebugLevel) {
277 js, _ := json.Marshal(flowMod)
Andrea Campanella91c4e4e2020-03-05 16:52:06 +0100278 logger.Debugw("handleFlowMod called",
David K. Bainbridge157bdab2020-01-16 14:38:05 -0800279 log.Fields{
280 "device-id": ofc.DeviceID,
281 "flow-mod": js})
282 }
283 logger.Errorw("handleFlowMod not implemented",
284 log.Fields{"device-id": ofc.DeviceID})
285}
286
Jonathan Hart4b110f62020-03-13 17:36:19 -0700287func (ofc *OFConnection) handleFlowModStrict(flowModStrict *ofp.FlowModifyStrict) {
David K. Bainbridge157bdab2020-01-16 14:38:05 -0800288 if logger.V(log.DebugLevel) {
289 js, _ := json.Marshal(flowModStrict)
290 logger.Debugw("handleFlowModStrict called",
291 log.Fields{
292 "device-id": ofc.DeviceID,
293 "flow-mod-strict": js})
294 }
295 logger.Error("handleFlowModStrict not implemented",
296 log.Fields{"device-id": ofc.DeviceID})
297}
298
Jonathan Hart4b110f62020-03-13 17:36:19 -0700299func (ofc *OFConnection) handleFlowDelete(flowDelete *ofp.FlowDelete) {
David K. Bainbridge157bdab2020-01-16 14:38:05 -0800300 if logger.V(log.DebugLevel) {
301 js, _ := json.Marshal(flowDelete)
302 logger.Debugw("handleFlowDelete called",
303 log.Fields{
304 "device-id": ofc.DeviceID,
305 "flow-delete": js})
306 }
307 logger.Error("handleFlowDelete not implemented",
308 log.Fields{"device-id": ofc.DeviceID})
309
310}
311
Jonathan Hart4b110f62020-03-13 17:36:19 -0700312func (ofc *OFConnection) handleFlowDeleteStrict(flowDeleteStrict *ofp.FlowDeleteStrict) {
David K. Bainbridge157bdab2020-01-16 14:38:05 -0800313 if logger.V(log.DebugLevel) {
314 js, _ := json.Marshal(flowDeleteStrict)
Andrea Campanella91c4e4e2020-03-05 16:52:06 +0100315 logger.Debugw("handleFlowDeleteStrict called",
David K. Bainbridge157bdab2020-01-16 14:38:05 -0800316 log.Fields{
317 "device-id": ofc.DeviceID,
318 "flow-delete-strict": js})
319 }
320
David Bainbridgef8ce7d22020-04-08 12:49:41 -0700321 volthaClient := ofc.VolthaClient.Get()
322 if volthaClient == nil {
David K. Bainbridge9cb404e2020-01-28 14:32:29 -0800323 logger.Errorw("no-voltha-connection",
324 log.Fields{"device-id": ofc.DeviceID})
325 return
326 }
327
David K. Bainbridge157bdab2020-01-16 14:38:05 -0800328 // Construct match
329 var oxmList []*voltha.OfpOxmField
330 for _, oxmField := range flowDeleteStrict.Match.GetOxmList() {
331 name := oxmMap[oxmField.GetOXMName()]
332 val := oxmField.GetOXMValue()
333 var ofpOxmField voltha.OfpOxmField
334 ofpOxmField.OxmClass = ofp.OFPXMCOpenflowBasic
335 var field voltha.OfpOxmOfbField
336 field.Type = voltha.OxmOfbFieldTypes(name)
337
338 var x openflow_13.OfpOxmField_OfbField
339 x.OfbField = &field
340 ofpOxmField.Field = &x
341
342 switch voltha.OxmOfbFieldTypes(name) {
343 case voltha.OxmOfbFieldTypes_OFPXMT_OFB_IN_PORT:
344 field.Value = &voltha.OfpOxmOfbField_Port{
345 Port: uint32(val.(ofp.Port)),
346 }
347 case voltha.OxmOfbFieldTypes_OFPXMT_OFB_IN_PHY_PORT:
348 field.Value = &voltha.OfpOxmOfbField_PhysicalPort{
349 PhysicalPort: val.(uint32),
350 }
351 case voltha.OxmOfbFieldTypes_OFPXMT_OFB_METADATA:
352 field.Value = &voltha.OfpOxmOfbField_TableMetadata{
353 TableMetadata: val.(uint64),
354 }
355 case voltha.OxmOfbFieldTypes_OFPXMT_OFB_ETH_TYPE:
356 field.Value = &voltha.OfpOxmOfbField_EthType{
357 EthType: uint32(val.(ofp.EthernetType)),
358 }
359 case voltha.OxmOfbFieldTypes_OFPXMT_OFB_IP_PROTO:
360 field.Value = &voltha.OfpOxmOfbField_IpProto{
361 IpProto: uint32(val.(ofp.IpPrototype)),
362 }
Jonathan Hart60c5d772020-03-30 18:28:40 -0700363 case voltha.OxmOfbFieldTypes_OFPXMT_OFB_IPV4_DST:
364 field.Value = &voltha.OfpOxmOfbField_Ipv4Dst{
365 Ipv4Dst: binary.BigEndian.Uint32(val.(net.IP)),
366 }
David K. Bainbridge157bdab2020-01-16 14:38:05 -0800367 case voltha.OxmOfbFieldTypes_OFPXMT_OFB_UDP_SRC:
368 field.Value = &voltha.OfpOxmOfbField_UdpSrc{
369 UdpSrc: uint32(val.(uint16)),
370 }
371 case voltha.OxmOfbFieldTypes_OFPXMT_OFB_UDP_DST:
372 field.Value = &voltha.OfpOxmOfbField_UdpDst{
373 UdpDst: uint32(val.(uint16)),
374 }
375 case voltha.OxmOfbFieldTypes_OFPXMT_OFB_VLAN_VID:
376 field.Value = &voltha.OfpOxmOfbField_VlanVid{
377 VlanVid: uint32(val.(uint16)),
378 }
Don Newton7fe70f72020-02-21 13:54:11 -0500379 case 200: // voltha-protos doesn't actually have a type for vlan_mask
380 field = voltha.OfpOxmOfbField{Type: voltha.OxmOfbFieldTypes(oxmMap["vlan_vid"])}
381 field.HasMask = true
382 ofpOxmField = voltha.OfpOxmField{
383 OxmClass: ofp.OFPXMCOpenflowBasic,
384 Field: &openflow_13.OfpOxmField_OfbField{OfbField: &field},
385 }
386 field.Value = &voltha.OfpOxmOfbField_VlanVid{
387 VlanVid: uint32(val.(uint16)),
388 }
389 vidMask := val.(uint16)
390 field.Mask = &voltha.OfpOxmOfbField_VlanVidMask{
391 VlanVidMask: uint32(vidMask),
392 }
David K. Bainbridge157bdab2020-01-16 14:38:05 -0800393 }
Don Newton7fe70f72020-02-21 13:54:11 -0500394
David K. Bainbridge157bdab2020-01-16 14:38:05 -0800395 oxmList = append(oxmList, &ofpOxmField)
396 }
397
398 // Construct request
399 flowUpdate := openflow_13.FlowTableUpdate{
400 Id: ofc.DeviceID,
401 FlowMod: &voltha.OfpFlowMod{
402 Cookie: flowDeleteStrict.Cookie,
403 CookieMask: flowDeleteStrict.CookieMask,
404 TableId: uint32(flowDeleteStrict.TableId),
405 Command: voltha.OfpFlowModCommand_OFPFC_DELETE_STRICT,
406 IdleTimeout: uint32(flowDeleteStrict.IdleTimeout),
407 HardTimeout: uint32(flowDeleteStrict.HardTimeout),
408 Priority: uint32(flowDeleteStrict.Priority),
409 BufferId: flowDeleteStrict.BufferId,
410 OutPort: uint32(flowDeleteStrict.OutPort),
411 OutGroup: uint32(flowDeleteStrict.OutGroup),
412 Flags: uint32(flowDeleteStrict.Flags),
413 Match: &voltha.OfpMatch{
414 Type: voltha.OfpMatchType(flowDeleteStrict.Match.GetType()),
415 OxmFields: oxmList,
416 },
417 },
418 }
419
420 if logger.V(log.DebugLevel) {
421 flowUpdateJs, _ := json.Marshal(flowUpdate)
Andrea Campanella91c4e4e2020-03-05 16:52:06 +0100422 logger.Debugf("FlowDeleteStrict being sent to Voltha",
David K. Bainbridge157bdab2020-01-16 14:38:05 -0800423 log.Fields{
424 "device-id": ofc.DeviceID,
425 "flow-update": flowUpdateJs})
426 }
David Bainbridgef8ce7d22020-04-08 12:49:41 -0700427 if _, err := volthaClient.UpdateLogicalDeviceFlowTable(context.Background(), &flowUpdate); err != nil {
Andrea Campanella91c4e4e2020-03-05 16:52:06 +0100428 logger.Errorw("Error calling FlowDelete ",
David K. Bainbridge157bdab2020-01-16 14:38:05 -0800429 log.Fields{
430 "device-id": ofc.DeviceID,
431 "error": err})
432 }
433}