blob: 9d4596b41b39845ec3446a47a6ae0dc2a3723c27 [file] [log] [blame]
Takahiro Suzukid7bf8202020-12-17 20:21:59 +09001/*
2 * Copyright 2018-present Open Networking Foundation
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
17//Package core provides the utility for olt devices, flows and statistics
18package core
19
20import (
21 "context"
22
23 "github.com/opencord/voltha-lib-go/v3/pkg/flows"
24 "github.com/opencord/voltha-lib-go/v3/pkg/log"
25 "github.com/opencord/voltha-openolt-adapter/internal/pkg/olterrors"
26 ofp "github.com/opencord/voltha-protos/v3/go/openflow_13"
27 "github.com/opencord/voltha-protos/v3/go/voltha"
28)
29
30/*=====================================================================
31
32@TODO: Looks like this Flow id concept below is not used anywhere
33 Propose to remove the below documentation of Flow Id on confirmation
34 of the same
35
36Flow id
37
38 Identifies a flow within a single OLT
39 Flow Id is unique per OLT
40 Multiple GEM ports can map to same flow id
41
42 13 11 4 0
43 +--------+--------------+------+
44 | pon id | onu id | Flow |
45 | | | idx |
46 +--------+--------------+------+
47
48 14 bits = 16384 flows (per OLT).
49
50 pon id = 4 bits = 16 PON ports
51 onu id = 7 bits = 128 ONUss per PON port
52 Flow index = 3 bits = 4 bi-directional flows per ONU
53 = 8 uni-directional flows per ONU
54
55
56Logical (OF) UNI port number
57
58 OpenFlow port number corresponding to PON UNI
59
60 20 12 4 0
61 +--+--------+--------------+------+
62 |0 | pon id | onu id |uni id|
63 +--+--------+--------------+------+
64
65 pon id = 8 bits = 256 PON ports
66 onu id = 8 bits = 256 ONUs per PON port
67
68Logical (OF) NNI port number
69
70 OpenFlow port number corresponding to PON NNI
71
72 20 0
73 +--+----------------------------+
74 |1 | intf_id |
75 +--+----------------------------+
76
77 No overlap with UNI port number space
78
79
80PON OLT (OF) port number
81
82 OpenFlow port number corresponding to PON OLT ports
83
84 31 28 0
85 +--------+------------------------~~~------+
86 | 0x2 | pon intf id |
87 +--------+------------------------~~~------+
88*/
89
90const (
91 bitsForUniID = 4
92 bitsForONUID = 8
93 bitsForPONID = 8
94 MaxOnusPerPon = (1 << bitsForONUID)
95 MaxPonsPerOlt = (1 << bitsForPONID)
96 MaxUnisPerOnu = (1 << bitsForUniID)
97 nniUniDiffPos = (bitsForUniID + bitsForONUID + bitsForPONID)
98 ponIntfMarkerPos = 28
99 ponIntfMarkerValue = 0x2
100 bitsforNNIID = 20
101 minNniIntPortNum = (1 << bitsforNNIID)
102 maxNniPortNum = ((1 << (bitsforNNIID + 1)) - 1)
103)
104
105//MinUpstreamPortID value
106var MinUpstreamPortID = 0xfffd
107
108//MaxUpstreamPortID value
109var MaxUpstreamPortID = 0xfffffffd
110
111var controllerPorts = []uint32{0xfffd, 0x7ffffffd, 0xfffffffd}
112
113//MkUniPortNum returns new UNIportNum based on intfID, inuID and uniID
114func MkUniPortNum(ctx context.Context, intfID, onuID, uniID uint32) uint32 {
115 var limit = int(onuID)
116 if limit > MaxOnusPerPon {
117 logger.Warn(ctx, "exceeded-the-max-onus-per-pon")
118 }
119 return (intfID << (bitsForUniID + bitsForONUID)) | (onuID << bitsForUniID) | uniID
120}
121
122//OnuIDFromPortNum returns ONUID derived from portNumber
123func OnuIDFromPortNum(portNum uint32) uint32 {
124 return (portNum >> bitsForUniID) & (MaxOnusPerPon - 1)
125}
126
127//IntfIDFromUniPortNum returns IntfID derived from portNum
128func IntfIDFromUniPortNum(portNum uint32) uint32 {
129 return (portNum >> (bitsForUniID + bitsForONUID)) & (MaxPonsPerOlt - 1)
130}
131
132//UniIDFromPortNum return UniID derived from portNum
133func UniIDFromPortNum(portNum uint32) uint32 {
134 return (portNum) & (MaxUnisPerOnu - 1)
135}
136
137//IntfIDToPortNo returns portId derived from intftype, intfId and portType
138func IntfIDToPortNo(intfID uint32, intfType voltha.Port_PortType) uint32 {
139 if (intfType) == voltha.Port_ETHERNET_NNI {
140 return (1 << nniUniDiffPos) | intfID
141 }
142 if (intfType) == voltha.Port_PON_OLT {
143 return (ponIntfMarkerValue << ponIntfMarkerPos) | intfID
144 }
145 return 0
146}
147
148//PortNoToIntfID returns portnumber derived from interfaceID
149func PortNoToIntfID(portno uint32, intfType voltha.Port_PortType) uint32 {
150 if (intfType) == voltha.Port_ETHERNET_NNI {
151 return (1 << nniUniDiffPos) ^ portno
152 }
153 if (intfType) == voltha.Port_PON_OLT {
154 return (ponIntfMarkerValue << ponIntfMarkerPos) ^ portno
155 }
156 return 0
157}
158
159//IntfIDFromNniPortNum returns Intf ID derived from portNum
160func IntfIDFromNniPortNum(ctx context.Context, portNum uint32) (uint32, error) {
161 if portNum < minNniIntPortNum || portNum > maxNniPortNum {
162 logger.Errorw(ctx, "nniportnumber-is-not-in-valid-range", log.Fields{"portnum": portNum})
163 return uint32(0), olterrors.ErrInvalidPortRange
164 }
165 return (portNum & 0xFFFF), nil
166}
167
168//IntfIDToPortTypeName returns port type derived from the intfId
169func IntfIDToPortTypeName(intfID uint32) voltha.Port_PortType {
170 if ((ponIntfMarkerValue << ponIntfMarkerPos) ^ intfID) < MaxPonsPerOlt {
171 return voltha.Port_PON_OLT
172 }
173 if (intfID & (1 << nniUniDiffPos)) == (1 << nniUniDiffPos) {
174 return voltha.Port_ETHERNET_NNI
175 }
176 return voltha.Port_ETHERNET_UNI
177}
178
179//ExtractAccessFromFlow returns AccessDevice information
180func ExtractAccessFromFlow(inPort, outPort uint32) (uint32, uint32, uint32, uint32) {
181 if IsUpstream(outPort) {
182 return inPort, IntfIDFromUniPortNum(inPort), OnuIDFromPortNum(inPort), UniIDFromPortNum(inPort)
183 }
184 return outPort, IntfIDFromUniPortNum(outPort), OnuIDFromPortNum(outPort), UniIDFromPortNum(outPort)
185}
186
187//IsUpstream returns true for Upstream and false for downstream
188func IsUpstream(outPort uint32) bool {
189 for _, port := range controllerPorts {
190 if port == outPort {
191 return true
192 }
193 }
194 return (outPort & (1 << nniUniDiffPos)) == (1 << nniUniDiffPos)
195}
196
197//IsControllerBoundFlow returns true/false
198func IsControllerBoundFlow(outPort uint32) bool {
199 for _, port := range controllerPorts {
200 if port == outPort {
201 return true
202 }
203 }
204 return false
205}
206
207//OnuIDFromUniPortNum returns onuId from give portNum information.
208func OnuIDFromUniPortNum(portNum uint32) uint32 {
209 return (portNum >> bitsForUniID) & (MaxOnusPerPon - 1)
210}
211
212//FlowExtractInfo fetches uniport from the flow, based on which it gets and returns ponInf, onuID, uniID, inPort and ethType
213func FlowExtractInfo(ctx context.Context, flow *ofp.OfpFlowStats, flowDirection string) (uint32, uint32, uint32, uint32, uint32, uint32, error) {
214 var uniPortNo uint32
215 var ponIntf uint32
216 var onuID uint32
217 var uniID uint32
218 var inPort uint32
219 var ethType uint32
220
221 if flowDirection == "upstream" {
222 if uniPortNo = flows.GetChildPortFromTunnelId(flow); uniPortNo == 0 {
223 for _, field := range flows.GetOfbFields(flow) {
224 if field.GetType() == flows.IN_PORT {
225 uniPortNo = field.GetPort()
226 break
227 }
228 }
229 }
230 } else if flowDirection == "downstream" {
231 if uniPortNo = flows.GetChildPortFromTunnelId(flow); uniPortNo == 0 {
232 for _, field := range flows.GetOfbFields(flow) {
233 if field.GetType() == flows.METADATA {
234 for _, action := range flows.GetActions(flow) {
235 if action.Type == flows.OUTPUT {
236 if out := action.GetOutput(); out != nil {
237 uniPortNo = out.GetPort()
238 }
239 break
240 }
241 }
242 } else if field.GetType() == flows.IN_PORT {
243 inPort = field.GetPort()
244 } else if field.GetType() == flows.ETH_TYPE {
245 ethType = field.GetEthType()
246 }
247 }
248 }
249 }
250
251 if uniPortNo == 0 {
252 return 0, 0, 0, 0, 0, 0, olterrors.NewErrNotFound("pon-interface", log.Fields{"flow-direction": flowDirection}, nil)
253 }
254
255 ponIntf = IntfIDFromUniPortNum(uniPortNo)
256 onuID = OnuIDFromUniPortNum(uniPortNo)
257 uniID = UniIDFromPortNum(uniPortNo)
258
259 logger.Debugw(ctx, "flow-extract-info-result",
260 log.Fields{
261 "uniportno": uniPortNo,
262 "pon-intf": ponIntf,
263 "onu-id": onuID,
264 "uni-id": uniID,
265 "inport": inPort,
266 "ethtype": ethType})
267
268 return uniPortNo, ponIntf, onuID, uniID, inPort, ethType, nil
269}