blob: 73d1598a6ec0e2cb9bf78ab8b25fc930f526b1e0 [file] [log] [blame]
alshabibeff00542015-09-23 13:22:33 -07001/*
2 * Copyright 2014-2015 Open Networking Laboratory
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in reliance 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 */
16package org.onosproject.pim.impl;
17
18import org.jboss.netty.util.Timeout;
19import org.jboss.netty.util.TimerTask;
20import org.onlab.packet.IpAddress;
21import org.onlab.packet.MacAddress;
22import org.onlab.packet.pim.PIMHello;
23import org.onlab.packet.pim.PIMHelloOption;
24import org.onosproject.net.ConnectPoint;
25import org.slf4j.Logger;
26
27import java.nio.ByteBuffer;
28import java.util.concurrent.TimeUnit;
29
30import static com.google.common.base.Preconditions.checkNotNull;
31import static org.slf4j.LoggerFactory.getLogger;
32
33/**
34 * PIMNeighbor represents all the PIM routers that have sent us
35 * hello messages, or that possibly have been statically configured.
36 */
37public class PIMNeighbor {
38 private final Logger log = getLogger(getClass());
39
40 // The primary address of this PIM neighbor
41 private IpAddress primaryAddr;
42
43 // The MacAddress of this neighbor
44 private MacAddress macAddress;
45
46 // The ConnectPoint this PIM neighbor is connected to.
47 private ConnectPoint connectPoint;
48
49 // Is this neighbor us?
50 private boolean isThisUs = false;
51
52 // The option values this neighbor has sent us.
53 private int priority = 0;
54 private int genId = 0;
55 private short holdtime = 0;
56
57 // Is this pim neighbor the DR?
58 private boolean isDr = false;
59
60 // Timeout for this neighbor
61 private volatile Timeout timeout;
62
alshabibeff00542015-09-23 13:22:33 -070063 // A back pointer the neighbors list this neighbor belongs to.
Rusty Eddy95421642015-10-21 17:22:13 -070064 private PIMInterface pimInterface;
alshabibeff00542015-09-23 13:22:33 -070065
66 /**
67 * Construct this neighbor from the address and connect point.
68 *
69 * @param ipaddr IP Address of neighbor
70 * @param macaddr MAC Address of the neighbor
Rusty Eddy95421642015-10-21 17:22:13 -070071 * @param pimInterface The PIMInterface of this neighbor
alshabibeff00542015-09-23 13:22:33 -070072 */
Rusty Eddy95421642015-10-21 17:22:13 -070073 public PIMNeighbor(IpAddress ipaddr, MacAddress macaddr, PIMInterface pimInterface) {
alshabibeff00542015-09-23 13:22:33 -070074 this.macAddress = macaddr;
75 this.primaryAddr = ipaddr;
Rusty Eddy95421642015-10-21 17:22:13 -070076 this.pimInterface = pimInterface;
alshabibeff00542015-09-23 13:22:33 -070077 this.resetTimeout();
78 }
79
80 /**
81 * Get the primary address of this neighbor.
82 *
83 * @return the primary IP address.
84 */
85 public IpAddress getPrimaryAddr() {
86 return primaryAddr;
87 }
88
89 /**
90 * Set the primary address of this neighbor.
91 *
92 * @param primaryAddr the address we'll use when sending hello messages
93 */
94 public void setPrimaryAddr(IpAddress primaryAddr) {
95 this.primaryAddr = primaryAddr;
96 }
97
98 /**
99 * Get the priority this neighbor has advertised to us.
100 *
101 * @return the priority
102 */
103 public int getPriority() {
104 return priority;
105 }
106
107 /**
108 * Set the priority for this neighbor.
109 *
110 * @param priority This neighbors priority.
111 */
112 public void setPriority(int priority) {
113 this.priority = priority;
114 }
115
116 /**
117 * Get the generation ID.
118 *
119 * @return the generation ID.
120 */
121 public int getGenId() {
122 return genId;
123 }
124
125 /**
126 * Set the generation ID.
127 *
128 * @param genId the generation ID.
129 */
130 public void setGenId(int genId) {
131 this.genId = genId;
132 }
133
134 /**
135 * Get the holdtime for this neighbor.
136 *
137 * @return the holdtime
138 */
139 public short getHoldtime() {
140 return holdtime;
141 }
142
143 /**
144 * Set the holdtime for this neighbor.
145 *
146 * @param holdtime the holdtime.
147 */
148 public void setholdtime(short holdtime) {
149 this.holdtime = holdtime;
150 }
151
152 /**
153 * Is this neighbor the designated router on this connect point?
154 *
155 * @return true if so, false if not.
156 */
157 public boolean isDr() {
158 return isDr;
159 }
160
161 /**
162 * Set this router as the designated router on this connect point.
163 *
164 * @param isDr True is this neighbor is the DR false otherwise
165 */
166 public void setIsDr(boolean isDr) {
167 this.isDr = isDr;
168 }
169
170 /**
171 * The ConnectPoint this neighbor is connected to.
172 *
173 * @return the ConnectPoint
174 */
Rusty Eddy95421642015-10-21 17:22:13 -0700175 public PIMInterface getPimInterface() {
176 return pimInterface;
alshabibeff00542015-09-23 13:22:33 -0700177 }
178
179 /**
Rusty Eddy95421642015-10-21 17:22:13 -0700180 * We have received a fresh hello from this neighbor, now we need to process it.
alshabibeff00542015-09-23 13:22:33 -0700181 * Depending on the values received in the the hello options may force a
182 * re-election process.
183 *
184 * We will also refresh the timeout for this neighbor.
185 *
186 * @param hello copy of the hello we'll be able to extract options from.
187 */
188 public void refresh(PIMHello hello) {
189 checkNotNull(hello);
190
Rusty Eddy95421642015-10-21 17:22:13 -0700191 boolean reelect = false;
alshabibeff00542015-09-23 13:22:33 -0700192 for (PIMHelloOption opt : hello.getOptions().values()) {
193
194 int len = opt.getOptLength();
Rusty Eddy95421642015-10-21 17:22:13 -0700195 ByteBuffer bb = ByteBuffer.wrap(opt.getValue());
alshabibeff00542015-09-23 13:22:33 -0700196
197 switch (opt.getOptType()) {
198 case PIMHelloOption.OPT_GENID:
199 int newid = bb.getInt();
200 if (this.genId != newid) {
Rusty Eddy95421642015-10-21 17:22:13 -0700201
202 // We have a newly rebooted neighbor, this is where we would
203 // send them our joins.
alshabibeff00542015-09-23 13:22:33 -0700204 this.genId = newid;
205 }
206 break;
207
208 case PIMHelloOption.OPT_PRIORITY:
209 int newpri = bb.getInt();
210 if (this.priority != newpri) {
211
212 // The priorities have changed. We may need to re-elect a new DR?
Rusty Eddy95421642015-10-21 17:22:13 -0700213 if (this.isDr || pimInterface.getDesignatedRouter().getPriority() < priority) {
alshabibeff00542015-09-23 13:22:33 -0700214 reelect = true;
215 }
216 this.priority = newpri;
217 }
218 break;
219
220 case PIMHelloOption.OPT_HOLDTIME:
221 short holdtime = bb.getShort();
222 if (this.holdtime != holdtime) {
223 this.holdtime = holdtime;
224 if (holdtime == 0) {
225 // We have a neighbor going down. We can remove all joins
226 // we have learned from them.
alshabibeff00542015-09-23 13:22:33 -0700227
228 log.debug("PIM Neighbor has timed out: {}", this.primaryAddr.toString());
229 return;
230 }
231 }
232 break;
233
234 case PIMHelloOption.OPT_PRUNEDELAY:
235 case PIMHelloOption.OPT_ADDRLIST:
236 // TODO: implement prune delay and addr list. Fall through for now.
237
238 default:
239 log.debug("PIM Hello option type: {} not yet supported or unknown.", opt.getOptType());
240 break;
241 }
242 }
243
244 if (reelect) {
Rusty Eddy95421642015-10-21 17:22:13 -0700245 pimInterface.electDR(this);
alshabibeff00542015-09-23 13:22:33 -0700246 }
247
248 // Reset the next timeout timer
249 this.resetTimeout();
250 }
251
252 /* --------------------------------------- Timer functions -------------------------- */
253
254 /**
255 * Restart the timeout task for this neighbor.
256 */
257 private void resetTimeout() {
258
259 if (this.holdtime == 0) {
260
261 // Prepare to die.
262 log.debug("shutting down timer for nbr {}", this.primaryAddr.toString());
263 if (this.timeout != null) {
264 this.timeout.cancel();
265 this.timeout = null;
266 }
267 return;
268 }
269
270 // Cancel the existing timeout and start a fresh new one.
271 if (this.timeout != null) {
272 this.timeout.cancel();
273 }
274
275 this.timeout = PIMTimer.getTimer().newTimeout(new NeighborTimeoutTask(this), holdtime, TimeUnit.SECONDS);
276 }
277
278 /**
279 * The task to run when a neighbor timeout expires.
280 */
281 private final class NeighborTimeoutTask implements TimerTask {
282 PIMNeighbor nbr;
283
284 NeighborTimeoutTask(PIMNeighbor nbr) {
285 this.nbr = nbr;
286 }
287
288 @Override
289 public void run(Timeout timeout) throws Exception {
290
Rusty Eddy95421642015-10-21 17:22:13 -0700291 log.debug("PIM Neighbor {} has timed out: ", nbr.toString());
292 nbr.pimInterface.removeNeighbor(nbr);
alshabibeff00542015-09-23 13:22:33 -0700293 }
294 }
295
296 /**
297 * Stop the timeout timer.
298 *
299 * This happens when we remove the neighbor.
300 */
301 private final void stopTimeout() {
302 this.timeout.cancel();
303 this.timeout = null;
304 }
305
306 @Override
307 public String toString() {
308 String out = "";
309 if (this.isDr) {
310 out += "*NBR:";
311 } else {
312 out += "NBR:";
313 }
314 out += "\tIP: " + this.primaryAddr.toString();
315 out += "\tPr: " + String.valueOf(this.priority);
316 out += "\tHoldTime: " + String.valueOf(this.holdtime);
317 out += "\tGenID: " + String.valueOf(this.genId) + "\n";
318 return out;
319 }
320}