blob: 5da5c2b32bf03610fe36b8cefb40306212beb82d [file] [log] [blame]
Rusty Eddy95421642015-10-21 17:22:13 -07001/*
2 * Copyright 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 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 */
16package org.onosproject.pim.impl;
17
18import org.onlab.packet.Ethernet;
19import org.onlab.packet.IPv4;
20import org.onlab.packet.Ip4Address;
21import org.onlab.packet.IpAddress;
22import org.onlab.packet.MacAddress;
23import org.onlab.packet.PIM;
24import org.onlab.packet.pim.PIMHello;
25import org.onlab.packet.pim.PIMHelloOption;
26import org.onosproject.incubator.net.intf.Interface;
27import org.onosproject.net.ConnectPoint;
28import org.onosproject.net.host.InterfaceIpAddress;
29import org.slf4j.Logger;
30import org.slf4j.LoggerFactory;
31
32import java.util.Collection;
33import java.util.HashMap;
34import java.util.Map;
35
36import static com.google.common.base.Preconditions.checkNotNull;
37
38/**
39 * The PIM Interface is a wrapper around a ConnectPoint and used to provide
40 * hello options values when "talking" with PIM other PIM routers.
41 */
42public class PIMInterface {
43 private static Logger log = LoggerFactory.getLogger("PIMInterfaces");
44
45 // Interface from the interface subsystem
46 private Interface theInterface;
47
48 // The list of PIM neighbors adjacent to this interface
49 private Map<IpAddress, PIMNeighbor> neighbors = new HashMap<>();
50
51 // The designatedRouter for this LAN
52 private PIMNeighbor designatedRouter;
53
54 // The priority we use on this ConnectPoint.
55 private int priority = PIMHelloOption.DEFAULT_PRIORITY;
56
57 // The holdtime we are sending out.
58 private int holdtime = PIMHelloOption.DEFAULT_HOLDTIME;
59
60 // Then generation ID we are sending out. 0 means we need to generate a new random ID
61 private int genid = PIMHelloOption.DEFAULT_GENID;
62
63 // Our default prune delay
64 private int prunedelay = PIMHelloOption.DEFAULT_PRUNEDELAY;
65
66 /**
67 * Create a PIMInterface.
Charles Chan30ba4002015-11-05 14:45:16 -080068 *
69 * @param intf the network interface configuration
Rusty Eddy95421642015-10-21 17:22:13 -070070 */
71 public PIMInterface(Interface intf) {
72
73 log.debug("Adding an interface: " + intf.toString() + "\n");
74 this.theInterface = intf;
75
76 // Send a hello to let our neighbors know we are alive
77 sendHello();
78 }
79
80 /**
81 * Get the PIM Interface.
82 *
83 * @return the PIM Interface
84 */
85 public Interface getInterface() {
86 return theInterface;
87 }
88
89 /**
90 * Getter for our IP address.
91 *
92 * @return our IP address.
93 */
94 public IpAddress getIpAddress() {
95 if (theInterface.ipAddresses().isEmpty()) {
96 return null;
97 }
98
99 // We will just assume the first interface on the list
100 IpAddress ipaddr = null;
101 for (InterfaceIpAddress ifipaddr : theInterface.ipAddresses()) {
102 ipaddr = ifipaddr.ipAddress();
103 break;
104 }
105 return ipaddr;
106 }
107
108 /**
109 * Get our priority.
110 *
111 * @return our priority.
112 */
113 public int getPriority() {
114 return this.priority;
115 }
116
117 /**
118 * Get the designated router on this connection.
119 *
120 * @return the PIMNeighbor representing the DR
121 */
122 public PIMNeighbor getDesignatedRouter() {
123 return designatedRouter;
124 }
125
126 /**
127 * Are we the DR on this CP?
128 *
129 * @return true if we are, false if not
130 */
131 public boolean areWeDr() {
132 return (designatedRouter != null &&
133 designatedRouter.getPrimaryAddr().equals(this.getIpAddress()));
134 }
135
136 /**
137 * Return a collection of PIM Neighbors.
138 *
139 * @return the collection of PIM Neighbors
140 */
141 public Collection<PIMNeighbor> getNeighbors() {
142 return this.neighbors.values();
143 }
144
145 /**
146 * Find the neighbor with the given IP address on this CP.
147 *
148 * @param ipaddr the IP address of the neighbor we are interested in
149 * @return the pim neighbor if it exists
150 */
151 public PIMNeighbor findNeighbor(IpAddress ipaddr) {
152 PIMNeighbor nbr = neighbors.get(ipaddr);
153 return nbr;
154 }
155
156 /**
157 * Add a new PIM neighbor to this list.
158 *
159 * @param nbr the neighbor to be added.
160 */
161 public void addNeighbor(PIMNeighbor nbr) {
162 if (neighbors.containsKey(nbr.getPrimaryAddr())) {
163
164 log.debug("We are adding a neighbor that already exists: {}", nbr.toString());
165 neighbors.remove(nbr.getPrimaryAddr());
166 }
167 neighbors.put(nbr.getPrimaryAddr(), nbr);
168 }
169
170 /**
171 * Remove the neighbor from our neighbor list.
172 *
173 * @param ipaddr the IP address of the neighbor to remove
174 */
175 public void removeNeighbor(IpAddress ipaddr) {
176
177 if (neighbors.containsKey(ipaddr)) {
178 neighbors.remove(ipaddr);
179 }
180 this.electDR();
181 }
182
183 /**
184 * Remove the given neighbor from the neighbor list.
185 *
186 * @param nbr the nbr to be removed.
187 */
188 public void removeNeighbor(PIMNeighbor nbr) {
189
190 neighbors.remove(nbr.getPrimaryAddr(), nbr);
191 this.electDR();
192 }
193
194 /**
195 * Elect a new DR on this ConnectPoint.
196 *
197 * @return the PIM Neighbor that wins
198 */
199 public PIMNeighbor electDR() {
200
201 for (PIMNeighbor nbr : this.neighbors.values()) {
202 if (this.designatedRouter == null) {
203 this.designatedRouter = nbr;
204 continue;
205 }
206
207 if (nbr.getPriority() > this.designatedRouter.getPriority()) {
208 this.designatedRouter = nbr;
209 continue;
210 }
211
212 // We could sort in ascending order
213 if (this.designatedRouter.getPrimaryAddr().compareTo(nbr.getPrimaryAddr()) > 0) {
214 this.designatedRouter = nbr;
215 continue;
216 }
217 }
218
219 return this.designatedRouter;
220 }
221
222 /**
223 * Elect a new DR given the new neighbor.
224 *
225 * @param nbr the new neighbor to use in DR election.
226 * @return the PIM Neighbor that wins DR election
227 */
228 public PIMNeighbor electDR(PIMNeighbor nbr) {
229
230 // Make sure I have
231 if (this.designatedRouter == null ||
232 this.designatedRouter.getPriority() < nbr.getPriority() ||
233 this.designatedRouter.getPrimaryAddr().compareTo(nbr.getPrimaryAddr()) > 0) {
234 this.designatedRouter = nbr;
235 }
236 return this.designatedRouter;
237 }
238
239 /**
240 * Find or create a pim neighbor with a given ip address and connect point.
241 *
242 * @param ipaddr of the pim neighbor
243 * @param mac The mac address of our sending neighbor
244 * @return an existing or new PIM neighbor
245 */
246 public PIMNeighbor findOrCreate(IpAddress ipaddr, MacAddress mac) {
247 PIMNeighbor nbr = this.findNeighbor(ipaddr);
248 if (nbr == null) {
249 nbr = new PIMNeighbor(ipaddr, mac, this);
250 this.addNeighbor(nbr);
251 this.electDR(nbr);
252 }
253 return nbr;
254 }
255
256 /**
257 * Process a hello packet received on this Interface.
258 *
259 * @param ethPkt the ethernet packet containing the hello message
260 * @param cp the ConnectPoint of this interface
261 */
262 public void processHello(Ethernet ethPkt, ConnectPoint cp) {
263 checkNotNull(ethPkt);
264 checkNotNull(cp);
265
266 MacAddress srcmac = ethPkt.getSourceMAC();
267 IPv4 ip = (IPv4) ethPkt.getPayload();
268 Ip4Address srcip = Ip4Address.valueOf(ip.getSourceAddress());
269
270 PIM pim = (PIM) ip.getPayload();
271 checkNotNull(pim);
272
273 PIMHello hello = (PIMHello) pim.getPayload();
274 checkNotNull(hello);
275
276 PIMNeighbor nbr = this.findOrCreate(srcip, srcmac);
277 if (nbr == null) {
278 log.error("Could not create a neighbor for: {1}", srcip.toString());
279 return;
280 }
281
282 ConnectPoint icp = theInterface.connectPoint();
283 checkNotNull(icp);
284 if (!cp.equals(icp)) {
285 log.error("PIM Hello message received from {} on incorrect interface {}",
286 nbr.getPrimaryAddr(), this.toString());
287 return;
288 }
289 nbr.refresh(hello);
290 }
291
292 /**
293 * Send a hello packet from this interface.
294 */
295 public void sendHello() {
296 PIM pim = new PIM();
297 PIMHello hello = new PIMHello();
298
299 // Create a PIM Hello
300 pim = new PIM();
301 pim.setVersion((byte) 2);
302 pim.setPIMType((byte) PIM.TYPE_HELLO);
303 pim.setChecksum((short) 0);
304
305 hello = new PIMHello();
306 hello.createDefaultOptions();
307 pim.setPayload(hello);
308 hello.setParent(pim);
309
310 log.debug("Sending hello: \n");
311 PIMPacketHandler.getInstance().sendPacket(pim, this);
312 }
313
314 /**
315 * prints the connectPointNeighbors list with each neighbor list.
316 *
317 * @return string of neighbors.
318 */
319 public String printNeighbors() {
320 String out = "PIM Neighbors Table: \n";
321 for (PIMNeighbor nbr : this.neighbors.values()) {
322 out += "\t" + nbr.toString();
323 }
324 return out;
325 }
326
327 @Override
328 public String toString() {
329 IpAddress ipaddr = this.getIpAddress();
330 String out = "PIM Neighbors: ";
331 if (ipaddr != null) {
332 out += "IP: " + ipaddr.toString();
333 } else {
334 out += "IP: *Null*";
335 }
336 out += "\tPR: " + String.valueOf(this.priority) + "\n";
337 return out;
338 }
339
340}
341