blob: 44cdb8e02436a9a557eceab70a834cd00ffd1466 [file] [log] [blame]
Naveen Sampath04696f72022-06-13 15:19:14 +05301/*
2* Copyright 2022-present Open Networking Foundation
3* Licensed under the Apache License, Version 2.0 (the "License");
4* you may not use this file except in compliance with the License.
5* You may obtain a copy of the License at
6*
7* http://www.apache.org/licenses/LICENSE-2.0
8*
9* Unless required by applicable law or agreed to in writing, software
10* distributed under the License is distributed on an "AS IS" BASIS,
11* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12* See the License for the specific language governing permissions and
13* limitations under the License.
14 */
15
16package application
17
18import (
19 "sync"
20 "time"
21
Tinoj Joseph1d108322022-07-13 10:07:39 +053022 "voltha-go-controller/log"
Naveen Sampath04696f72022-06-13 15:19:14 +053023)
24
25const (
26 dhcpTimeout uint8 = 60
27)
28
29// done channel required to gracefully stop dhcp server handler thread
30var done = make(chan bool)
31
32// dhcpServerInfo map having dhcp network as key and dhcp request response transaction as value
33var dhcpServerInfo map[dhcpServerTag]dhcpTransactionInfo
34
35// alarmsRaised is struct having array of dhcp network for which dhcp unreachable alarm raised
36var alarmsRaised alarmsRaisedInfo
37
38// mux is mutex variable used for lock unlock
39var mux sync.Mutex
40
41// StartDhcpServerHandler starts go routine periodically(every second) to verify DHCP server reachability.
42func StartDhcpServerHandler() {
vinokuma926cb3e2023-03-29 11:41:06 +053043 // Initialize global dhcp map and ticker as one second
Naveen Sampath04696f72022-06-13 15:19:14 +053044 dhcpServerInfo = make(map[dhcpServerTag]dhcpTransactionInfo)
45 ticker := time.NewTicker(1 * time.Second)
46
47 // go routine runs checkDhcpTimeout every second and exit if done value is set.
48 go func() {
49 for {
50 select {
51 case <-done:
52 ticker.Stop()
53 return
54 case <-ticker.C:
55 mux.Lock()
56 checkDhcpTimeout()
57 mux.Unlock()
Naveen Sampath04696f72022-06-13 15:19:14 +053058 }
59 }
60 }()
61}
62
63// checkDhcpTimeout method called every second to verify dhcp timeout for each DHCP network
64func checkDhcpTimeout() {
65 // logger.Debugw(ctx, "[dhcptimeout] DHCP MAP Info", log.Fields{"Map": dhcpServerInfo})
66 for dsTag, dtInfo := range dhcpServerInfo {
67 dtInfo.decrementTimer()
68 if dtInfo.getTimer() == 0 {
69 logger.Debugw(ctx, "[dhcptimeout]Timer Expired", log.Fields{"ctag": dsTag.cTag, "stag": dsTag.sTag})
70 if dtInfo.getReceivedResponseCount() == 0 && !alarmsRaised.isexist(dsTag) {
71 alarmsRaised.add(dsTag)
72 logger.Infow(ctx, "Alarms Raised", log.Fields{"ctag": dsTag.cTag, "stag": dsTag.sTag})
73 }
74
75 // Reset helps in
76 // case 1: when 2 requests, 1 response received within timeout interval.
77 // case 2: 1 request and no response even after timeout. (Unreachable alarm raised)
78 // In both cases, reset method provides additional timeout to receive response before deleting
79 dtInfo.resetRequestResponseCount(dhcpTimeout)
80
81 // Delete dhcp entry in map and continue to process next entry if pending request set to 0
82 if dtInfo.getPendingRequestCount() == 0 {
83 delete(dhcpServerInfo, dsTag)
84 logger.Debugw(ctx, "[dhcptimeout]DhcpServerTag info removed", log.Fields{"ctag": dsTag.cTag, "stag": dsTag.sTag})
85 // logger.Debugw(ctx, "[dhcptimeout] DHCP MAP Info", log.Fields{"Map": dhcpServerInfo})
86 continue
87 }
88 }
89 // Update decremented timer value and continue loop
90 dhcpServerInfo[dsTag] = dtInfo
91 }
92}
93
94// dhcpRequestReceived called for every DHCP request received from client.
95func dhcpRequestReceived(cTag, sTag uint16, smac string) {
96 var dtInfo dhcpTransactionInfo
97 var valueExist bool
98 dsTag := newDhcpServerTag(cTag, sTag)
99
100 mux.Lock()
101 logger.Debugw(ctx, "dhcpRequestReceived", log.Fields{"ctag": cTag, "stag": sTag, "smac": smac})
102 if dtInfo, valueExist = dhcpServerInfo[dsTag]; !valueExist {
103 dtInfo = newDhcpTransactionInfo(dhcpTimeout, smac)
104 dtInfo.incrementPendingRequestCount()
105 }
106
107 // Source mac received in dhcp request is not same as dtInfo mac then
108 // Its new subscriber request, hence increment pending request count.
109 // If multiple dhcp request received with same mac are ignored.
110 if dtInfo.smac != smac {
111 dtInfo.incrementPendingRequestCount()
112 }
113
114 dhcpServerInfo[dsTag] = dtInfo
115 mux.Unlock()
116}
117
118// dhcpResponseReceived called for every DHCP response received from dhcp server.
119func dhcpResponseReceived(cTag, sTag uint16) {
120 var dtInfo dhcpTransactionInfo
121 var valueExist bool
122 dsTag := newDhcpServerTag(cTag, sTag)
123
124 mux.Lock()
125 logger.Debugw(ctx, "dhcpResponseReceived", log.Fields{"ctag": cTag, "stag": sTag})
126 if dtInfo, valueExist = dhcpServerInfo[dsTag]; !valueExist {
127 logger.Warnw(ctx, "Ignore unknown response", log.Fields{"DhcpResp": dsTag})
128 mux.Unlock()
129 return
130 }
131
132 // If already unreachable alarm raised, clear and remove from array
133 if alarmsRaised.isexist(dsTag) {
134 alarmsRaised.remove(dsTag)
135 logger.Infow(ctx, "Alarm Cleared", log.Fields{"ctag": dsTag.cTag, "stag": dsTag.sTag})
136 }
137
138 // Increments received count and decrement pending count
139 dtInfo.responseReceived()
140 logger.Debugw(ctx, "Updated dtInfo", log.Fields{"pendingReq": dtInfo.pendingRequestCount, "receivedReq": dtInfo.receivedResponseCount})
141
142 if dtInfo.getPendingRequestCount() == 0 {
143 delete(dhcpServerInfo, dsTag)
144 } else {
145 dhcpServerInfo[dsTag] = dtInfo
146 }
147 mux.Unlock()
148}
149
150// StopDhcpServerHandler stops dhcp server handler go routine
151func StopDhcpServerHandler() {
152 done <- true
153}
154
155// dhcpServerTag contains unique dhcp network information
156type dhcpServerTag struct {
157 sTag uint16
158 cTag uint16
159}
160
161func newDhcpServerTag(cTag, sTag uint16) dhcpServerTag {
162 var d dhcpServerTag
163 d.sTag = sTag
164 d.cTag = cTag
165 return d
166}
167
168// dhcpTransactionInfo contains DHCP request response transaction information.
169type dhcpTransactionInfo struct {
vinokuma926cb3e2023-03-29 11:41:06 +0530170 smac string
Naveen Sampath04696f72022-06-13 15:19:14 +0530171 pendingRequestCount uint32
172 receivedResponseCount uint32
173 previousRequestCount uint32
vinokuma926cb3e2023-03-29 11:41:06 +0530174 timer uint8
Naveen Sampath04696f72022-06-13 15:19:14 +0530175}
176
177func newDhcpTransactionInfo(timer uint8, smac string) dhcpTransactionInfo {
178 var dt dhcpTransactionInfo
179 dt.timer = timer
180 dt.smac = smac
181 return dt
182}
183
184func (dt *dhcpTransactionInfo) getTimer() uint8 {
185 return dt.timer
186}
187
188func (dt *dhcpTransactionInfo) decrementTimer() uint8 {
189 dt.timer--
190 return dt.timer
191}
192
193func (dt *dhcpTransactionInfo) getPendingRequestCount() uint32 {
194 return dt.pendingRequestCount
195}
196
197func (dt *dhcpTransactionInfo) incrementPendingRequestCount() {
198 dt.pendingRequestCount++
199}
200
201func (dt *dhcpTransactionInfo) getReceivedResponseCount() uint32 {
202 return dt.receivedResponseCount
203}
204
205func (dt *dhcpTransactionInfo) responseReceived() {
206 dt.receivedResponseCount++
207 dt.pendingRequestCount--
208}
209
210func (dt *dhcpTransactionInfo) resetRequestResponseCount(timer uint8) {
211 if dt.pendingRequestCount >= dt.previousRequestCount {
212 dt.pendingRequestCount = dt.pendingRequestCount - dt.previousRequestCount
213 }
214 dt.previousRequestCount = dt.pendingRequestCount
215 dt.receivedResponseCount = 0
216 dt.timer = timer
217}
218
219// alarmsRaisedInfo contains the all networks alarm raised information
220type alarmsRaisedInfo struct {
221 arrayInfo []dhcpServerTag
222}
223
224// add an entry into alarm raised array
225func (a *alarmsRaisedInfo) add(val dhcpServerTag) {
226 a.arrayInfo = append(a.arrayInfo, val)
227}
228
229// isexist check if entry exist in alarm raised array
230func (a *alarmsRaisedInfo) isexist(val dhcpServerTag) bool {
231 for _, srvTag := range a.arrayInfo {
232 if srvTag == val {
233 return true
234 }
235 }
236 return false
237}
238
239// remove deletes given entry from alarm raised array
240func (a *alarmsRaisedInfo) remove(val dhcpServerTag) {
241 for ind := range a.arrayInfo {
242 if a.arrayInfo[ind] == val {
243 a.arrayInfo = append(a.arrayInfo[:ind], a.arrayInfo[ind+1:]...)
244 break
245 }
246 }
247}