blob: cabcfc238de0152c93730a82a11b34a2568a6f11 [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"
23 ofp "github.com/donNewtonAlpha/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"
Andrea Campanella30342622020-03-05 20:48:26 +010027 "unsafe"
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
74func (ofc *OFClient) handleFlowAdd(flowAdd *ofp.FlowAdd) {
75 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 K. Bainbridge9cb404e2020-01-28 14:32:29 -080083 if ofc.VolthaClient == nil {
84 logger.Errorw("no-voltha-connection",
85 log.Fields{"device-id": ofc.DeviceID})
86 return
87 }
88
David K. Bainbridge157bdab2020-01-16 14:38:05 -080089 // Construct the match
90 var oxmList []*voltha.OfpOxmField
91 for _, oxmField := range flowAdd.Match.GetOxmList() {
92 name := oxmMap[oxmField.GetOXMName()]
93 val := oxmField.GetOXMValue()
94 field := voltha.OfpOxmOfbField{Type: voltha.OxmOfbFieldTypes(name)}
95 ofpOxmField := voltha.OfpOxmField{
96 OxmClass: ofp.OFPXMCOpenflowBasic,
97 Field: &openflow_13.OfpOxmField_OfbField{OfbField: &field},
98 }
99 switch voltha.OxmOfbFieldTypes(name) {
100 case voltha.OxmOfbFieldTypes_OFPXMT_OFB_IN_PORT:
101 field.Value = &voltha.OfpOxmOfbField_Port{
102 Port: uint32(val.(ofp.Port)),
103 }
104 case voltha.OxmOfbFieldTypes_OFPXMT_OFB_IN_PHY_PORT:
105 field.Value = &voltha.OfpOxmOfbField_PhysicalPort{
106 PhysicalPort: val.(uint32),
107 }
108 case voltha.OxmOfbFieldTypes_OFPXMT_OFB_METADATA:
109 field.Value = &voltha.OfpOxmOfbField_TableMetadata{
110 TableMetadata: val.(uint64),
111 }
112 case voltha.OxmOfbFieldTypes_OFPXMT_OFB_ETH_TYPE:
113 field.Value = &voltha.OfpOxmOfbField_EthType{
114 EthType: uint32(val.(ofp.EthernetType)),
115 }
116 case voltha.OxmOfbFieldTypes_OFPXMT_OFB_IP_PROTO:
117 field.Value = &voltha.OfpOxmOfbField_IpProto{
118 IpProto: uint32(val.(ofp.IpPrototype)),
119 }
120 case voltha.OxmOfbFieldTypes_OFPXMT_OFB_UDP_SRC:
121 field.Value = &voltha.OfpOxmOfbField_UdpSrc{
122 UdpSrc: uint32(val.(uint16)),
123 }
124 case voltha.OxmOfbFieldTypes_OFPXMT_OFB_UDP_DST:
125 field.Value = &voltha.OfpOxmOfbField_UdpDst{
126 UdpDst: uint32(val.(uint16)),
127 }
128 case voltha.OxmOfbFieldTypes_OFPXMT_OFB_VLAN_VID:
129 field.Value = &voltha.OfpOxmOfbField_VlanVid{
130 VlanVid: uint32((val.(uint16) & 0xfff) | 0x1000),
131 }
Don Newton7fe70f72020-02-21 13:54:11 -0500132 case 200: // voltha-protos doesn't actually have a type for vlan_mask
133 field = voltha.OfpOxmOfbField{Type: voltha.OxmOfbFieldTypes(oxmMap["vlan_vid"])}
134 field.HasMask = true
135 ofpOxmField = voltha.OfpOxmField{
136 OxmClass: ofp.OFPXMCOpenflowBasic,
137 Field: &openflow_13.OfpOxmField_OfbField{OfbField: &field},
138 }
139 field.Value = &voltha.OfpOxmOfbField_VlanVid{
140 VlanVid: uint32(val.(uint16)),
141 }
142 vidMask := val.(uint16)
143 field.Mask = &voltha.OfpOxmOfbField_VlanVidMask{
144 VlanVidMask: uint32(vidMask),
145 }
David K. Bainbridge157bdab2020-01-16 14:38:05 -0800146 }
147 oxmList = append(oxmList, &ofpOxmField)
148 }
149
150 // Construct the instructions
151 var instructions []*voltha.OfpInstruction
152 for _, ofpInstruction := range flowAdd.GetInstructions() {
153 instructionType := ofpInstruction.GetType()
154 instruction := voltha.OfpInstruction{Type: uint32(instructionType)}
155 switch instructionType {
156 case ofp.OFPITGotoTable:
157 instruction.Data = &openflow_13.OfpInstruction_GotoTable{
158 GotoTable: &openflow_13.OfpInstructionGotoTable{
159 TableId: uint32(ofpInstruction.(ofp.IInstructionGotoTable).GetTableId()),
160 },
161 }
162 case ofp.OFPITWriteMetadata:
163 instruction.Data = &openflow_13.OfpInstruction_WriteMetadata{
164 WriteMetadata: &openflow_13.OfpInstructionWriteMetadata{
165 Metadata: ofpInstruction.(ofp.IInstructionWriteMetadata).GetMetadata(),
166 MetadataMask: ofpInstruction.(ofp.IInstructionWriteMetadata).GetMetadataMask(),
167 },
168 }
169 case ofp.OFPITWriteActions:
170 var ofpActions []*openflow_13.OfpAction
171 for _, action := range ofpInstruction.(ofp.IInstructionWriteActions).GetActions() {
172 ofpActions = append(ofpActions, extractAction(action))
173 }
174 instruction.Data = &openflow_13.OfpInstruction_Actions{
175 Actions: &openflow_13.OfpInstructionActions{
176 Actions: ofpActions,
177 },
178 }
179 case ofp.OFPITApplyActions:
180 var ofpActions []*openflow_13.OfpAction
181 for _, action := range ofpInstruction.(ofp.IInstructionApplyActions).GetActions() {
182 ofpActions = append(ofpActions, extractAction(action))
183 }
184 instruction.Data = &openflow_13.OfpInstruction_Actions{
185 Actions: &openflow_13.OfpInstructionActions{
186 Actions: ofpActions,
187 },
188 }
189 case ofp.OFPITMeter:
190 instruction.Data = &openflow_13.OfpInstruction_Meter{
191 Meter: &openflow_13.OfpInstructionMeter{
192 MeterId: ofpInstruction.(ofp.IInstructionMeter).GetMeterId(),
193 },
194 }
195 }
196 instructions = append(instructions, &instruction)
197 }
198
199 // Construct the request
200 flowUpdate := openflow_13.FlowTableUpdate{
201 Id: ofc.DeviceID,
202 FlowMod: &voltha.OfpFlowMod{
203 Cookie: flowAdd.Cookie,
204 CookieMask: flowAdd.CookieMask,
205 TableId: uint32(flowAdd.TableId),
206 Command: voltha.OfpFlowModCommand_OFPFC_ADD,
207 IdleTimeout: uint32(flowAdd.IdleTimeout),
208 HardTimeout: uint32(flowAdd.HardTimeout),
209 Priority: uint32(flowAdd.Priority),
210 BufferId: flowAdd.BufferId,
211 OutPort: uint32(flowAdd.OutPort),
212 OutGroup: uint32(flowAdd.OutGroup),
213 Flags: uint32(flowAdd.Flags),
214 Match: &voltha.OfpMatch{
215 Type: voltha.OfpMatchType(flowAdd.Match.GetType()),
216 OxmFields: oxmList,
217 },
218
219 Instructions: instructions,
220 },
221 }
222 if logger.V(log.DebugLevel) {
223 flowUpdateJs, _ := json.Marshal(flowUpdate)
Andrea Campanella91c4e4e2020-03-05 16:52:06 +0100224 logger.Debugf("FlowAdd being sent to Voltha",
David K. Bainbridge157bdab2020-01-16 14:38:05 -0800225 log.Fields{
226 "device-id": ofc.DeviceID,
Don Newton7fe70f72020-02-21 13:54:11 -0500227 "flow-mod-object": flowUpdate,
David K. Bainbridge157bdab2020-01-16 14:38:05 -0800228 "flow-mod-request": flowUpdateJs})
229 }
230 if _, err := ofc.VolthaClient.UpdateLogicalDeviceFlowTable(context.Background(), &flowUpdate); err != nil {
Andrea Campanella91c4e4e2020-03-05 16:52:06 +0100231 logger.Errorw("Error calling FlowAdd ",
David K. Bainbridge157bdab2020-01-16 14:38:05 -0800232 log.Fields{
233 "device-id": ofc.DeviceID,
234 "error": err})
Andrea Campanella30342622020-03-05 20:48:26 +0100235 // Report failure to controller
236 message := ofp.NewFlowModFailedErrorMsg()
237 message.SetXid(flowAdd.Xid)
238 message.SetCode(ofp.OFPFMFCBadCommand)
239 //OF 1.3
240 message.SetVersion(4)
241 bs := make([]byte, 2)
242 //OF 1.3
243 bs[0] = byte(4)
244 //Flow Mod
245 bs[1] = byte(14)
246 //Length of the message
247 length := make([]byte, 2)
248 binary.BigEndian.PutUint16(length, 56)
249 bs = append(bs, length...)
250 empty := []byte{0, 0, 0, 0}
251 bs = append(bs, empty...)
252 //Cookie of the Flow
253 cookie := make([]byte, 52)
254 binary.BigEndian.PutUint64(cookie, flowAdd.Cookie)
255 bs = append(bs, cookie...)
256 message.SetData(bs)
257 message.Length = uint16(unsafe.Sizeof(*message))
258 err := ofc.SendMessage(message)
259 if err != nil {
260 logger.Errorw("Error reporting failure of FlowUpdate to controller",
261 log.Fields{
262 "device-id": ofc.DeviceID,
263 "error": err})
264 }
David K. Bainbridge157bdab2020-01-16 14:38:05 -0800265 }
266}
267
268func (ofc *OFClient) handleFlowMod(flowMod *ofp.FlowMod) {
269 if logger.V(log.DebugLevel) {
270 js, _ := json.Marshal(flowMod)
Andrea Campanella91c4e4e2020-03-05 16:52:06 +0100271 logger.Debugw("handleFlowMod called",
David K. Bainbridge157bdab2020-01-16 14:38:05 -0800272 log.Fields{
273 "device-id": ofc.DeviceID,
274 "flow-mod": js})
275 }
276 logger.Errorw("handleFlowMod not implemented",
277 log.Fields{"device-id": ofc.DeviceID})
278}
279
280func (ofc *OFClient) handleFlowModStrict(flowModStrict *ofp.FlowModifyStrict) {
281 if logger.V(log.DebugLevel) {
282 js, _ := json.Marshal(flowModStrict)
283 logger.Debugw("handleFlowModStrict called",
284 log.Fields{
285 "device-id": ofc.DeviceID,
286 "flow-mod-strict": js})
287 }
288 logger.Error("handleFlowModStrict not implemented",
289 log.Fields{"device-id": ofc.DeviceID})
290}
291
292func (ofc *OFClient) handleFlowDelete(flowDelete *ofp.FlowDelete) {
293 if logger.V(log.DebugLevel) {
294 js, _ := json.Marshal(flowDelete)
295 logger.Debugw("handleFlowDelete called",
296 log.Fields{
297 "device-id": ofc.DeviceID,
298 "flow-delete": js})
299 }
300 logger.Error("handleFlowDelete not implemented",
301 log.Fields{"device-id": ofc.DeviceID})
302
303}
304
305func (ofc *OFClient) handleFlowDeleteStrict(flowDeleteStrict *ofp.FlowDeleteStrict) {
306 if logger.V(log.DebugLevel) {
307 js, _ := json.Marshal(flowDeleteStrict)
Andrea Campanella91c4e4e2020-03-05 16:52:06 +0100308 logger.Debugw("handleFlowDeleteStrict called",
David K. Bainbridge157bdab2020-01-16 14:38:05 -0800309 log.Fields{
310 "device-id": ofc.DeviceID,
311 "flow-delete-strict": js})
312 }
313
David K. Bainbridge9cb404e2020-01-28 14:32:29 -0800314 if ofc.VolthaClient == nil {
315 logger.Errorw("no-voltha-connection",
316 log.Fields{"device-id": ofc.DeviceID})
317 return
318 }
319
David K. Bainbridge157bdab2020-01-16 14:38:05 -0800320 // Construct match
321 var oxmList []*voltha.OfpOxmField
322 for _, oxmField := range flowDeleteStrict.Match.GetOxmList() {
323 name := oxmMap[oxmField.GetOXMName()]
324 val := oxmField.GetOXMValue()
325 var ofpOxmField voltha.OfpOxmField
326 ofpOxmField.OxmClass = ofp.OFPXMCOpenflowBasic
327 var field voltha.OfpOxmOfbField
328 field.Type = voltha.OxmOfbFieldTypes(name)
329
330 var x openflow_13.OfpOxmField_OfbField
331 x.OfbField = &field
332 ofpOxmField.Field = &x
333
334 switch voltha.OxmOfbFieldTypes(name) {
335 case voltha.OxmOfbFieldTypes_OFPXMT_OFB_IN_PORT:
336 field.Value = &voltha.OfpOxmOfbField_Port{
337 Port: uint32(val.(ofp.Port)),
338 }
339 case voltha.OxmOfbFieldTypes_OFPXMT_OFB_IN_PHY_PORT:
340 field.Value = &voltha.OfpOxmOfbField_PhysicalPort{
341 PhysicalPort: val.(uint32),
342 }
343 case voltha.OxmOfbFieldTypes_OFPXMT_OFB_METADATA:
344 field.Value = &voltha.OfpOxmOfbField_TableMetadata{
345 TableMetadata: val.(uint64),
346 }
347 case voltha.OxmOfbFieldTypes_OFPXMT_OFB_ETH_TYPE:
348 field.Value = &voltha.OfpOxmOfbField_EthType{
349 EthType: uint32(val.(ofp.EthernetType)),
350 }
351 case voltha.OxmOfbFieldTypes_OFPXMT_OFB_IP_PROTO:
352 field.Value = &voltha.OfpOxmOfbField_IpProto{
353 IpProto: uint32(val.(ofp.IpPrototype)),
354 }
355 case voltha.OxmOfbFieldTypes_OFPXMT_OFB_UDP_SRC:
356 field.Value = &voltha.OfpOxmOfbField_UdpSrc{
357 UdpSrc: uint32(val.(uint16)),
358 }
359 case voltha.OxmOfbFieldTypes_OFPXMT_OFB_UDP_DST:
360 field.Value = &voltha.OfpOxmOfbField_UdpDst{
361 UdpDst: uint32(val.(uint16)),
362 }
363 case voltha.OxmOfbFieldTypes_OFPXMT_OFB_VLAN_VID:
364 field.Value = &voltha.OfpOxmOfbField_VlanVid{
365 VlanVid: uint32(val.(uint16)),
366 }
Don Newton7fe70f72020-02-21 13:54:11 -0500367 case 200: // voltha-protos doesn't actually have a type for vlan_mask
368 field = voltha.OfpOxmOfbField{Type: voltha.OxmOfbFieldTypes(oxmMap["vlan_vid"])}
369 field.HasMask = true
370 ofpOxmField = voltha.OfpOxmField{
371 OxmClass: ofp.OFPXMCOpenflowBasic,
372 Field: &openflow_13.OfpOxmField_OfbField{OfbField: &field},
373 }
374 field.Value = &voltha.OfpOxmOfbField_VlanVid{
375 VlanVid: uint32(val.(uint16)),
376 }
377 vidMask := val.(uint16)
378 field.Mask = &voltha.OfpOxmOfbField_VlanVidMask{
379 VlanVidMask: uint32(vidMask),
380 }
David K. Bainbridge157bdab2020-01-16 14:38:05 -0800381 }
Don Newton7fe70f72020-02-21 13:54:11 -0500382
David K. Bainbridge157bdab2020-01-16 14:38:05 -0800383 oxmList = append(oxmList, &ofpOxmField)
384 }
385
386 // Construct request
387 flowUpdate := openflow_13.FlowTableUpdate{
388 Id: ofc.DeviceID,
389 FlowMod: &voltha.OfpFlowMod{
390 Cookie: flowDeleteStrict.Cookie,
391 CookieMask: flowDeleteStrict.CookieMask,
392 TableId: uint32(flowDeleteStrict.TableId),
393 Command: voltha.OfpFlowModCommand_OFPFC_DELETE_STRICT,
394 IdleTimeout: uint32(flowDeleteStrict.IdleTimeout),
395 HardTimeout: uint32(flowDeleteStrict.HardTimeout),
396 Priority: uint32(flowDeleteStrict.Priority),
397 BufferId: flowDeleteStrict.BufferId,
398 OutPort: uint32(flowDeleteStrict.OutPort),
399 OutGroup: uint32(flowDeleteStrict.OutGroup),
400 Flags: uint32(flowDeleteStrict.Flags),
401 Match: &voltha.OfpMatch{
402 Type: voltha.OfpMatchType(flowDeleteStrict.Match.GetType()),
403 OxmFields: oxmList,
404 },
405 },
406 }
407
408 if logger.V(log.DebugLevel) {
409 flowUpdateJs, _ := json.Marshal(flowUpdate)
Andrea Campanella91c4e4e2020-03-05 16:52:06 +0100410 logger.Debugf("FlowDeleteStrict being sent to Voltha",
David K. Bainbridge157bdab2020-01-16 14:38:05 -0800411 log.Fields{
412 "device-id": ofc.DeviceID,
413 "flow-update": flowUpdateJs})
414 }
415 if _, err := ofc.VolthaClient.UpdateLogicalDeviceFlowTable(context.Background(), &flowUpdate); err != nil {
Andrea Campanella91c4e4e2020-03-05 16:52:06 +0100416 logger.Errorw("Error calling FlowDelete ",
David K. Bainbridge157bdab2020-01-16 14:38:05 -0800417 log.Fields{
418 "device-id": ofc.DeviceID,
419 "error": err})
420 }
421}