blob: bd8ea4a7b47531d17f35acfe9968f60b56757747 [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 }
David K. Bainbridge157bdab2020-01-16 14:38:05 -0800125 case voltha.OxmOfbFieldTypes_OFPXMT_OFB_UDP_SRC:
126 field.Value = &voltha.OfpOxmOfbField_UdpSrc{
127 UdpSrc: uint32(val.(uint16)),
128 }
129 case voltha.OxmOfbFieldTypes_OFPXMT_OFB_UDP_DST:
130 field.Value = &voltha.OfpOxmOfbField_UdpDst{
131 UdpDst: uint32(val.(uint16)),
132 }
133 case voltha.OxmOfbFieldTypes_OFPXMT_OFB_VLAN_VID:
134 field.Value = &voltha.OfpOxmOfbField_VlanVid{
135 VlanVid: uint32((val.(uint16) & 0xfff) | 0x1000),
136 }
Don Newton7fe70f72020-02-21 13:54:11 -0500137 case 200: // voltha-protos doesn't actually have a type for vlan_mask
138 field = voltha.OfpOxmOfbField{Type: voltha.OxmOfbFieldTypes(oxmMap["vlan_vid"])}
139 field.HasMask = true
140 ofpOxmField = voltha.OfpOxmField{
141 OxmClass: ofp.OFPXMCOpenflowBasic,
142 Field: &openflow_13.OfpOxmField_OfbField{OfbField: &field},
143 }
144 field.Value = &voltha.OfpOxmOfbField_VlanVid{
145 VlanVid: uint32(val.(uint16)),
146 }
147 vidMask := val.(uint16)
148 field.Mask = &voltha.OfpOxmOfbField_VlanVidMask{
149 VlanVidMask: uint32(vidMask),
150 }
David K. Bainbridge157bdab2020-01-16 14:38:05 -0800151 }
152 oxmList = append(oxmList, &ofpOxmField)
153 }
154
155 // Construct the instructions
156 var instructions []*voltha.OfpInstruction
157 for _, ofpInstruction := range flowAdd.GetInstructions() {
158 instructionType := ofpInstruction.GetType()
159 instruction := voltha.OfpInstruction{Type: uint32(instructionType)}
160 switch instructionType {
161 case ofp.OFPITGotoTable:
162 instruction.Data = &openflow_13.OfpInstruction_GotoTable{
163 GotoTable: &openflow_13.OfpInstructionGotoTable{
164 TableId: uint32(ofpInstruction.(ofp.IInstructionGotoTable).GetTableId()),
165 },
166 }
167 case ofp.OFPITWriteMetadata:
168 instruction.Data = &openflow_13.OfpInstruction_WriteMetadata{
169 WriteMetadata: &openflow_13.OfpInstructionWriteMetadata{
170 Metadata: ofpInstruction.(ofp.IInstructionWriteMetadata).GetMetadata(),
171 MetadataMask: ofpInstruction.(ofp.IInstructionWriteMetadata).GetMetadataMask(),
172 },
173 }
174 case ofp.OFPITWriteActions:
175 var ofpActions []*openflow_13.OfpAction
176 for _, action := range ofpInstruction.(ofp.IInstructionWriteActions).GetActions() {
177 ofpActions = append(ofpActions, extractAction(action))
178 }
179 instruction.Data = &openflow_13.OfpInstruction_Actions{
180 Actions: &openflow_13.OfpInstructionActions{
181 Actions: ofpActions,
182 },
183 }
184 case ofp.OFPITApplyActions:
185 var ofpActions []*openflow_13.OfpAction
186 for _, action := range ofpInstruction.(ofp.IInstructionApplyActions).GetActions() {
187 ofpActions = append(ofpActions, extractAction(action))
188 }
189 instruction.Data = &openflow_13.OfpInstruction_Actions{
190 Actions: &openflow_13.OfpInstructionActions{
191 Actions: ofpActions,
192 },
193 }
194 case ofp.OFPITMeter:
195 instruction.Data = &openflow_13.OfpInstruction_Meter{
196 Meter: &openflow_13.OfpInstructionMeter{
197 MeterId: ofpInstruction.(ofp.IInstructionMeter).GetMeterId(),
198 },
199 }
200 }
201 instructions = append(instructions, &instruction)
202 }
203
204 // Construct the request
205 flowUpdate := openflow_13.FlowTableUpdate{
206 Id: ofc.DeviceID,
207 FlowMod: &voltha.OfpFlowMod{
208 Cookie: flowAdd.Cookie,
209 CookieMask: flowAdd.CookieMask,
210 TableId: uint32(flowAdd.TableId),
211 Command: voltha.OfpFlowModCommand_OFPFC_ADD,
212 IdleTimeout: uint32(flowAdd.IdleTimeout),
213 HardTimeout: uint32(flowAdd.HardTimeout),
214 Priority: uint32(flowAdd.Priority),
215 BufferId: flowAdd.BufferId,
216 OutPort: uint32(flowAdd.OutPort),
217 OutGroup: uint32(flowAdd.OutGroup),
218 Flags: uint32(flowAdd.Flags),
219 Match: &voltha.OfpMatch{
220 Type: voltha.OfpMatchType(flowAdd.Match.GetType()),
221 OxmFields: oxmList,
222 },
223
224 Instructions: instructions,
225 },
226 }
227 if logger.V(log.DebugLevel) {
228 flowUpdateJs, _ := json.Marshal(flowUpdate)
Andrea Campanella91c4e4e2020-03-05 16:52:06 +0100229 logger.Debugf("FlowAdd being sent to Voltha",
David K. Bainbridge157bdab2020-01-16 14:38:05 -0800230 log.Fields{
231 "device-id": ofc.DeviceID,
Don Newton7fe70f72020-02-21 13:54:11 -0500232 "flow-mod-object": flowUpdate,
David K. Bainbridge157bdab2020-01-16 14:38:05 -0800233 "flow-mod-request": flowUpdateJs})
234 }
David Bainbridgef8ce7d22020-04-08 12:49:41 -0700235 if _, err := volthaClient.UpdateLogicalDeviceFlowTable(context.Background(), &flowUpdate); err != nil {
Andrea Campanella91c4e4e2020-03-05 16:52:06 +0100236 logger.Errorw("Error calling FlowAdd ",
David K. Bainbridge157bdab2020-01-16 14:38:05 -0800237 log.Fields{
238 "device-id": ofc.DeviceID,
239 "error": err})
Andrea Campanella30342622020-03-05 20:48:26 +0100240 // Report failure to controller
241 message := ofp.NewFlowModFailedErrorMsg()
242 message.SetXid(flowAdd.Xid)
243 message.SetCode(ofp.OFPFMFCBadCommand)
244 //OF 1.3
245 message.SetVersion(4)
246 bs := make([]byte, 2)
247 //OF 1.3
248 bs[0] = byte(4)
249 //Flow Mod
250 bs[1] = byte(14)
251 //Length of the message
252 length := make([]byte, 2)
253 binary.BigEndian.PutUint16(length, 56)
254 bs = append(bs, length...)
255 empty := []byte{0, 0, 0, 0}
256 bs = append(bs, empty...)
257 //Cookie of the Flow
258 cookie := make([]byte, 52)
259 binary.BigEndian.PutUint64(cookie, flowAdd.Cookie)
260 bs = append(bs, cookie...)
261 message.SetData(bs)
Andrea Campanella30342622020-03-05 20:48:26 +0100262 err := ofc.SendMessage(message)
263 if err != nil {
264 logger.Errorw("Error reporting failure of FlowUpdate to controller",
265 log.Fields{
266 "device-id": ofc.DeviceID,
267 "error": err})
268 }
David K. Bainbridge157bdab2020-01-16 14:38:05 -0800269 }
270}
271
Jonathan Hart4b110f62020-03-13 17:36:19 -0700272func (ofc *OFConnection) handleFlowMod(flowMod *ofp.FlowMod) {
David K. Bainbridge157bdab2020-01-16 14:38:05 -0800273 if logger.V(log.DebugLevel) {
274 js, _ := json.Marshal(flowMod)
Andrea Campanella91c4e4e2020-03-05 16:52:06 +0100275 logger.Debugw("handleFlowMod called",
David K. Bainbridge157bdab2020-01-16 14:38:05 -0800276 log.Fields{
277 "device-id": ofc.DeviceID,
278 "flow-mod": js})
279 }
280 logger.Errorw("handleFlowMod not implemented",
281 log.Fields{"device-id": ofc.DeviceID})
282}
283
Jonathan Hart4b110f62020-03-13 17:36:19 -0700284func (ofc *OFConnection) handleFlowModStrict(flowModStrict *ofp.FlowModifyStrict) {
David K. Bainbridge157bdab2020-01-16 14:38:05 -0800285 if logger.V(log.DebugLevel) {
286 js, _ := json.Marshal(flowModStrict)
287 logger.Debugw("handleFlowModStrict called",
288 log.Fields{
289 "device-id": ofc.DeviceID,
290 "flow-mod-strict": js})
291 }
292 logger.Error("handleFlowModStrict not implemented",
293 log.Fields{"device-id": ofc.DeviceID})
294}
295
Jonathan Hart4b110f62020-03-13 17:36:19 -0700296func (ofc *OFConnection) handleFlowDelete(flowDelete *ofp.FlowDelete) {
David K. Bainbridge157bdab2020-01-16 14:38:05 -0800297 if logger.V(log.DebugLevel) {
298 js, _ := json.Marshal(flowDelete)
299 logger.Debugw("handleFlowDelete called",
300 log.Fields{
301 "device-id": ofc.DeviceID,
302 "flow-delete": js})
303 }
304 logger.Error("handleFlowDelete not implemented",
305 log.Fields{"device-id": ofc.DeviceID})
306
307}
308
Jonathan Hart4b110f62020-03-13 17:36:19 -0700309func (ofc *OFConnection) handleFlowDeleteStrict(flowDeleteStrict *ofp.FlowDeleteStrict) {
David K. Bainbridge157bdab2020-01-16 14:38:05 -0800310 if logger.V(log.DebugLevel) {
311 js, _ := json.Marshal(flowDeleteStrict)
Andrea Campanella91c4e4e2020-03-05 16:52:06 +0100312 logger.Debugw("handleFlowDeleteStrict called",
David K. Bainbridge157bdab2020-01-16 14:38:05 -0800313 log.Fields{
314 "device-id": ofc.DeviceID,
315 "flow-delete-strict": js})
316 }
317
David Bainbridgef8ce7d22020-04-08 12:49:41 -0700318 volthaClient := ofc.VolthaClient.Get()
319 if volthaClient == nil {
David K. Bainbridge9cb404e2020-01-28 14:32:29 -0800320 logger.Errorw("no-voltha-connection",
321 log.Fields{"device-id": ofc.DeviceID})
322 return
323 }
324
David K. Bainbridge157bdab2020-01-16 14:38:05 -0800325 // Construct match
326 var oxmList []*voltha.OfpOxmField
327 for _, oxmField := range flowDeleteStrict.Match.GetOxmList() {
328 name := oxmMap[oxmField.GetOXMName()]
329 val := oxmField.GetOXMValue()
330 var ofpOxmField voltha.OfpOxmField
331 ofpOxmField.OxmClass = ofp.OFPXMCOpenflowBasic
332 var field voltha.OfpOxmOfbField
333 field.Type = voltha.OxmOfbFieldTypes(name)
334
335 var x openflow_13.OfpOxmField_OfbField
336 x.OfbField = &field
337 ofpOxmField.Field = &x
338
339 switch voltha.OxmOfbFieldTypes(name) {
340 case voltha.OxmOfbFieldTypes_OFPXMT_OFB_IN_PORT:
341 field.Value = &voltha.OfpOxmOfbField_Port{
342 Port: uint32(val.(ofp.Port)),
343 }
344 case voltha.OxmOfbFieldTypes_OFPXMT_OFB_IN_PHY_PORT:
345 field.Value = &voltha.OfpOxmOfbField_PhysicalPort{
346 PhysicalPort: val.(uint32),
347 }
348 case voltha.OxmOfbFieldTypes_OFPXMT_OFB_METADATA:
349 field.Value = &voltha.OfpOxmOfbField_TableMetadata{
350 TableMetadata: val.(uint64),
351 }
352 case voltha.OxmOfbFieldTypes_OFPXMT_OFB_ETH_TYPE:
353 field.Value = &voltha.OfpOxmOfbField_EthType{
354 EthType: uint32(val.(ofp.EthernetType)),
355 }
356 case voltha.OxmOfbFieldTypes_OFPXMT_OFB_IP_PROTO:
357 field.Value = &voltha.OfpOxmOfbField_IpProto{
358 IpProto: uint32(val.(ofp.IpPrototype)),
359 }
Jonathan Hart60c5d772020-03-30 18:28:40 -0700360 case voltha.OxmOfbFieldTypes_OFPXMT_OFB_IPV4_DST:
361 field.Value = &voltha.OfpOxmOfbField_Ipv4Dst{
362 Ipv4Dst: binary.BigEndian.Uint32(val.(net.IP)),
363 }
David K. Bainbridge157bdab2020-01-16 14:38:05 -0800364 case voltha.OxmOfbFieldTypes_OFPXMT_OFB_UDP_SRC:
365 field.Value = &voltha.OfpOxmOfbField_UdpSrc{
366 UdpSrc: uint32(val.(uint16)),
367 }
368 case voltha.OxmOfbFieldTypes_OFPXMT_OFB_UDP_DST:
369 field.Value = &voltha.OfpOxmOfbField_UdpDst{
370 UdpDst: uint32(val.(uint16)),
371 }
372 case voltha.OxmOfbFieldTypes_OFPXMT_OFB_VLAN_VID:
373 field.Value = &voltha.OfpOxmOfbField_VlanVid{
374 VlanVid: uint32(val.(uint16)),
375 }
Don Newton7fe70f72020-02-21 13:54:11 -0500376 case 200: // voltha-protos doesn't actually have a type for vlan_mask
377 field = voltha.OfpOxmOfbField{Type: voltha.OxmOfbFieldTypes(oxmMap["vlan_vid"])}
378 field.HasMask = true
379 ofpOxmField = voltha.OfpOxmField{
380 OxmClass: ofp.OFPXMCOpenflowBasic,
381 Field: &openflow_13.OfpOxmField_OfbField{OfbField: &field},
382 }
383 field.Value = &voltha.OfpOxmOfbField_VlanVid{
384 VlanVid: uint32(val.(uint16)),
385 }
386 vidMask := val.(uint16)
387 field.Mask = &voltha.OfpOxmOfbField_VlanVidMask{
388 VlanVidMask: uint32(vidMask),
389 }
David K. Bainbridge157bdab2020-01-16 14:38:05 -0800390 }
Don Newton7fe70f72020-02-21 13:54:11 -0500391
David K. Bainbridge157bdab2020-01-16 14:38:05 -0800392 oxmList = append(oxmList, &ofpOxmField)
393 }
394
395 // Construct request
396 flowUpdate := openflow_13.FlowTableUpdate{
397 Id: ofc.DeviceID,
398 FlowMod: &voltha.OfpFlowMod{
399 Cookie: flowDeleteStrict.Cookie,
400 CookieMask: flowDeleteStrict.CookieMask,
401 TableId: uint32(flowDeleteStrict.TableId),
402 Command: voltha.OfpFlowModCommand_OFPFC_DELETE_STRICT,
403 IdleTimeout: uint32(flowDeleteStrict.IdleTimeout),
404 HardTimeout: uint32(flowDeleteStrict.HardTimeout),
405 Priority: uint32(flowDeleteStrict.Priority),
406 BufferId: flowDeleteStrict.BufferId,
407 OutPort: uint32(flowDeleteStrict.OutPort),
408 OutGroup: uint32(flowDeleteStrict.OutGroup),
409 Flags: uint32(flowDeleteStrict.Flags),
410 Match: &voltha.OfpMatch{
411 Type: voltha.OfpMatchType(flowDeleteStrict.Match.GetType()),
412 OxmFields: oxmList,
413 },
414 },
415 }
416
417 if logger.V(log.DebugLevel) {
418 flowUpdateJs, _ := json.Marshal(flowUpdate)
Andrea Campanella91c4e4e2020-03-05 16:52:06 +0100419 logger.Debugf("FlowDeleteStrict being sent to Voltha",
David K. Bainbridge157bdab2020-01-16 14:38:05 -0800420 log.Fields{
421 "device-id": ofc.DeviceID,
422 "flow-update": flowUpdateJs})
423 }
David Bainbridgef8ce7d22020-04-08 12:49:41 -0700424 if _, err := volthaClient.UpdateLogicalDeviceFlowTable(context.Background(), &flowUpdate); err != nil {
Andrea Campanella91c4e4e2020-03-05 16:52:06 +0100425 logger.Errorw("Error calling FlowDelete ",
David K. Bainbridge157bdab2020-01-16 14:38:05 -0800426 log.Fields{
427 "device-id": ofc.DeviceID,
428 "error": err})
429 }
430}