blob: e0ae994ef84ee86ba7493fd7733608a69965d5f1 [file] [log] [blame]
David K. Bainbridged77028f2017-08-01 12:47:55 -07001/*
Brian O'Connor4d084702017-08-03 22:45:58 -07002 * Copyright 2017-present Open Networking Foundation
David K. Bainbridged77028f2017-08-01 12:47:55 -07003 *
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 */
developere400c582020-03-24 19:42:08 +010016package org.opencord.igmpproxy.impl;
ke han81a38b92017-03-10 18:41:44 +080017
ke han81a38b92017-03-10 18:41:44 +080018import org.onlab.packet.Ip4Address;
19import org.onosproject.net.DeviceId;
Esin Karaman00e16b72020-02-21 10:32:39 +000020import org.onosproject.net.PortNumber;
Ilayda Ozdemir4c5947c2020-05-05 13:14:32 +000021import org.opencord.igmpproxy.impl.state.DelayMember;
22import org.opencord.igmpproxy.impl.state.IdleMember;
23import org.opencord.igmpproxy.impl.state.NonMember;
24import org.opencord.igmpproxy.statemachine.StateMachine;
25import org.opencord.igmpproxy.statemachine.State;
26import org.opencord.igmpproxy.statemachine.StateMachineId;
Andrea Campanella2c70a572020-06-05 13:31:45 +020027import org.slf4j.Logger;
28import org.slf4j.LoggerFactory;
ke han81a38b92017-03-10 18:41:44 +080029
Esin Karamanb38700c2019-09-17 13:01:25 +000030import java.util.concurrent.atomic.AtomicInteger;
ke han81a38b92017-03-10 18:41:44 +080031
Sonal Kasliwalddc3ff22019-11-18 11:52:49 +000032
Ilayda Ozdemir4c5947c2020-05-05 13:14:32 +000033/**
34 * State machine implementation.
35 */
36public final class SingleStateMachine implements StateMachine {
37 public static final int DEFAULT_MAX_RESP = 0xfffffff;
38
Andrea Campanella2c70a572020-06-05 13:31:45 +020039 private Logger log = LoggerFactory.getLogger(getClass());
40
Ilayda Ozdemir4c5947c2020-05-05 13:14:32 +000041 private StateMachineId stateMachineId;
42 private int currentState;
43
ke han81a38b92017-03-10 18:41:44 +080044 private Ip4Address srcIp;
Esin Karaman00e16b72020-02-21 10:32:39 +000045 private PortNumber upLinkPort;
ke han81a38b92017-03-10 18:41:44 +080046
Ilayda Ozdemir4c5947c2020-05-05 13:14:32 +000047 private AtomicInteger timeOut; // unit is 1 second
48 private State[] states;
ke han81a38b92017-03-10 18:41:44 +080049 private int[] nonTransition =
Ilayda Ozdemir4c5947c2020-05-05 13:14:32 +000050 {State.STATE_DELAY, State.STATE_NON,
51 State.STATE_NON, State.STATE_NON};
ke han81a38b92017-03-10 18:41:44 +080052 private int[] delayTransition =
Ilayda Ozdemir4c5947c2020-05-05 13:14:32 +000053 {State.STATE_DELAY, State.STATE_NON,
54 State.STATE_DELAY, State.STATE_IDLE};
ke han81a38b92017-03-10 18:41:44 +080055 private int[] idleTransition =
Ilayda Ozdemir4c5947c2020-05-05 13:14:32 +000056 {State.STATE_IDLE, State.STATE_NON,
57 State.STATE_DELAY, State.STATE_IDLE};
ke han81a38b92017-03-10 18:41:44 +080058 //THE TRANSITION TABLE
59 private int[][] transition =
60 {nonTransition, delayTransition, idleTransition};
ke han81a38b92017-03-10 18:41:44 +080061
Ilayda Ozdemir4c5947c2020-05-05 13:14:32 +000062 /**
63 * Constructor for serializer.
64 */
65 private SingleStateMachine() {
66 this.stateMachineId = null;
67 this.srcIp = null;
68 this.upLinkPort = null;
69 this.timeOut = null;
70 this.states = null;
71 }
72
73 /**
74 * Constructor of single state machine.
75 *
76 * @param deviceId device id of state-machine
77 * @param groupIp group id of state-machine
78 * @param srcIp source ip of state-machine
79 * @param upLinkPort uplink port of state-machine
80 */
81 public SingleStateMachine(DeviceId deviceId,
82 Ip4Address groupIp,
83 Ip4Address srcIp,
84 PortNumber upLinkPort) {
85 this.stateMachineId = StateMachineId.of(deviceId, groupIp);
86 this.srcIp = srcIp;
Esin Karaman00e16b72020-02-21 10:32:39 +000087 this.upLinkPort = upLinkPort;
Ilayda Ozdemir4c5947c2020-05-05 13:14:32 +000088 this.currentState = State.STATE_NON;
89 this.timeOut = null;
90 this.states = new State[]{new NonMember(this), new DelayMember(this), new IdleMember(this)};
ke han81a38b92017-03-10 18:41:44 +080091 }
92
Ilayda Ozdemir4c5947c2020-05-05 13:14:32 +000093 /**
94 * Constructor of single state machine.
95 *
96 * @param machineId id of state-machine
97 * @param srcIp source ip of state-machine
98 * @param upLinkPort uplink port of state-machine
99 * @param currentState current state of state-machine
100 * @param timeout timeout value of state-machine
101 */
102 public SingleStateMachine(StateMachineId machineId,
103 Ip4Address srcIp,
104 PortNumber upLinkPort,
105 int currentState,
106 Integer timeout) {
107 this.stateMachineId = machineId;
108 this.srcIp = srcIp;
109 this.upLinkPort = upLinkPort;
110 this.currentState = currentState;
111 if (timeout != null) {
112 createTimeOut(timeout);
ke han81a38b92017-03-10 18:41:44 +0800113 } else {
Ilayda Ozdemir4c5947c2020-05-05 13:14:32 +0000114 this.timeOut = null;
ke han81a38b92017-03-10 18:41:44 +0800115 }
Ilayda Ozdemir4c5947c2020-05-05 13:14:32 +0000116 this.states = new State[]{new NonMember(this), new DelayMember(this), new IdleMember(this)};
ke han81a38b92017-03-10 18:41:44 +0800117 }
118
Ilayda Ozdemir4c5947c2020-05-05 13:14:32 +0000119 @Override
120 public StateMachineId getStateMachineId() {
121 return this.stateMachineId;
ke han81a38b92017-03-10 18:41:44 +0800122 }
Ilayda Ozdemir4c5947c2020-05-05 13:14:32 +0000123
124 @Override
125 public Ip4Address getGroupIp() {
126 return this.stateMachineId.getGroupIp();
127 }
128
129 @Override
130 public DeviceId getDeviceId() {
131 return this.stateMachineId.getDeviceId();
132 }
133
134
135 @Override
136 public Ip4Address getSrcIp() {
137 return srcIp;
138 }
139
140 public PortNumber getUpLinkPort() {
141 return upLinkPort;
142 }
143
144 @Override
ke han81a38b92017-03-10 18:41:44 +0800145 public int currentState() {
Ilayda Ozdemir4c5947c2020-05-05 13:14:32 +0000146 return this.currentState;
147 }
148
149 public Integer getTimeOut() {
150 return timeOut == null ? null : timeOut.get();
151 }
152
153 @Override
154 public void increaseTimeOut() {
155 this.timeOut.getAndIncrement();
156 }
157
158 @Override
159 public void decreaseTimeOut() {
160 this.timeOut.getAndDecrement();
161 }
162
163 @Override
164 public void setMaxTimeout() {
165 this.timeOut.set(DEFAULT_MAX_RESP);
166 }
167
168 @Override
169 public void startTimer(int timeout) {
170 createTimeOut(timeout);
171 }
172
173 @Override
174 public void resetTimer(int timeout) {
175 setTimeOut(timeout);
176 }
177
178 @Override
179 public void destroyTimer() {
180 setTimeOut(null);
181 }
182
183 @Override
184 public void join(boolean messageOutAllowed) {
185 if (messageOutAllowed) {
186 State state = states[currentState];
187 state.join();
188 }
189 next(State.TRANSITION_JOIN);
190 }
191
192 @Override
193 public void leave(boolean messageOutAllowed) {
194 if (messageOutAllowed) {
195 State state = states[currentState];
196 state.leave();
197 }
198 next(State.TRANSITION_LEAVE);
199 }
200
201 @Override
202 public void query(int maxResp) {
203 State state = states[currentState];
204 state.query(maxResp);
205 next(State.TRANSITION_QUERY);
206 }
207
208 @Override
209 public void timeOut(boolean sendQuery) {
210 if (sendQuery) {
211 State state = states[currentState];
212 state.timeOut();
213 }
214 next(State.TRANSITION_TIMEOUT);
ke han81a38b92017-03-10 18:41:44 +0800215 }
216
217 private void next(int msg) {
Andrea Campanella2c70a572020-06-05 13:31:45 +0200218 log.debug("Transitioning to State {}", msg);
Ilayda Ozdemir4c5947c2020-05-05 13:14:32 +0000219 this.currentState = transition[currentState][msg];
ke han81a38b92017-03-10 18:41:44 +0800220 }
221
Ilayda Ozdemir4c5947c2020-05-05 13:14:32 +0000222 private void setTimeOut(int timeout) {
223 timeOut.set(timeout);
ke han81a38b92017-03-10 18:41:44 +0800224 }
225
Ilayda Ozdemir4c5947c2020-05-05 13:14:32 +0000226 private void setTimeOut(Integer timeout) {
227 if (timeout == null) {
228 timeOut = null;
229 } else {
230 timeOut.set(timeout);
ke han81a38b92017-03-10 18:41:44 +0800231 }
232 }
233
Ilayda Ozdemir4c5947c2020-05-05 13:14:32 +0000234 private void createTimeOut(Integer timeout) {
235 timeOut = new AtomicInteger(timeout);
ke han81a38b92017-03-10 18:41:44 +0800236 }
237}