Rusty Eddy
Committed by Gerrit Code Review

Added PIM neighbors

Change-Id: Ibce9741be02b9e79e53780adc2ce272698a70ee6
...@@ -26,8 +26,11 @@ import org.onosproject.incubator.net.intf.Interface; ...@@ -26,8 +26,11 @@ import org.onosproject.incubator.net.intf.Interface;
26 import org.onosproject.net.host.InterfaceIpAddress; 26 import org.onosproject.net.host.InterfaceIpAddress;
27 import org.slf4j.Logger; 27 import org.slf4j.Logger;
28 28
29 +import java.util.HashMap;
30 +import java.util.Map;
29 import java.util.Set; 31 import java.util.Set;
30 32
33 +import static com.google.common.base.Preconditions.checkNotNull;
31 import static org.slf4j.LoggerFactory.getLogger; 34 import static org.slf4j.LoggerFactory.getLogger;
32 35
33 /** 36 /**
...@@ -52,6 +55,12 @@ public class PIMInterface { ...@@ -52,6 +55,12 @@ public class PIMInterface {
52 // Our current genid 55 // Our current genid
53 private int genid = PIMHelloOption.DEFAULT_GENID; // Needs to be assigned. 56 private int genid = PIMHelloOption.DEFAULT_GENID; // Needs to be assigned.
54 57
58 + // The IP address of the DR
59 + IpAddress drIpaddress;
60 +
61 + // A map of all our PIM neighbors keyed on our neighbors IP address
62 + private Map<IpAddress, PIMNeighbor> pimNeighbors = new HashMap<>();
63 +
55 /** 64 /**
56 * Create a PIMInterface from an ONOS Interface. 65 * Create a PIMInterface from an ONOS Interface.
57 * 66 *
...@@ -59,6 +68,17 @@ public class PIMInterface { ...@@ -59,6 +68,17 @@ public class PIMInterface {
59 */ 68 */
60 public PIMInterface(Interface intf) { 69 public PIMInterface(Interface intf) {
61 onosInterface = intf; 70 onosInterface = intf;
71 + IpAddress ourIp = getIpAddress();
72 + MacAddress mac = intf.mac();
73 +
74 + // Create a PIM Neighbor to represent ourselves for DR election.
75 + PIMNeighbor us = new PIMNeighbor(ourIp, mac);
76 +
77 + // Priority and IP address are all we need to DR election.
78 + us.setPriority(priority);
79 +
80 + pimNeighbors.put(ourIp, us);
81 + drIpaddress = ourIp;
62 } 82 }
63 83
64 /** 84 /**
...@@ -67,7 +87,8 @@ public class PIMInterface { ...@@ -67,7 +87,8 @@ public class PIMInterface {
67 * @return ONOS Interface. 87 * @return ONOS Interface.
68 */ 88 */
69 public Interface getInterface() { 89 public Interface getInterface() {
70 - return this.onosInterface; 90 + return onosInterface;
91 +
71 } 92 }
72 93
73 /** 94 /**
...@@ -76,7 +97,7 @@ public class PIMInterface { ...@@ -76,7 +97,7 @@ public class PIMInterface {
76 * @param intf ONOS Interface. 97 * @param intf ONOS Interface.
77 */ 98 */
78 public PIMInterface setInterface(Interface intf) { 99 public PIMInterface setInterface(Interface intf) {
79 - this.onosInterface = intf; 100 + onosInterface = intf;
80 return this; 101 return this;
81 } 102 }
82 103
...@@ -86,7 +107,7 @@ public class PIMInterface { ...@@ -86,7 +107,7 @@ public class PIMInterface {
86 * @return a set of Ip Addresses on this interface 107 * @return a set of Ip Addresses on this interface
87 */ 108 */
88 public Set<InterfaceIpAddress> getIpAddresses() { 109 public Set<InterfaceIpAddress> getIpAddresses() {
89 - return this.onosInterface.ipAddresses(); 110 + return onosInterface.ipAddresses();
90 } 111 }
91 112
92 /** 113 /**
...@@ -113,7 +134,7 @@ public class PIMInterface { ...@@ -113,7 +134,7 @@ public class PIMInterface {
113 * @return the holdtime 134 * @return the holdtime
114 */ 135 */
115 public short getHoldtime() { 136 public short getHoldtime() {
116 - return this.holdtime; 137 + return holdtime;
117 } 138 }
118 139
119 /** 140 /**
...@@ -122,7 +143,7 @@ public class PIMInterface { ...@@ -122,7 +143,7 @@ public class PIMInterface {
122 * @return The prune delay 143 * @return The prune delay
123 */ 144 */
124 public int getPruneDelay() { 145 public int getPruneDelay() {
125 - return this.pruneDelay; 146 + return pruneDelay;
126 } 147 }
127 148
128 /** 149 /**
...@@ -131,7 +152,7 @@ public class PIMInterface { ...@@ -131,7 +152,7 @@ public class PIMInterface {
131 * @return our priority 152 * @return our priority
132 */ 153 */
133 public int getPriority() { 154 public int getPriority() {
134 - return this.priority; 155 + return priority;
135 } 156 }
136 157
137 /** 158 /**
...@@ -140,11 +161,18 @@ public class PIMInterface { ...@@ -140,11 +161,18 @@ public class PIMInterface {
140 * @return our generation ID 161 * @return our generation ID
141 */ 162 */
142 public int getGenid() { 163 public int getGenid() {
143 - return this.genid; 164 + return genid;
144 } 165 }
145 166
146 /** 167 /**
147 - * Process an incoming PIM Hello message. 168 + * Process an incoming PIM Hello message. There are a few things going on in
169 + * this method:
170 + * <ul>
171 + * <li>We <em>may</em> have to create a new neighbor if one does not already exist</li>
172 + * <li>We <em>may</em> need to re-elect a new DR if new information is received</li>
173 + * <li>We <em>may</em> need to send an existing neighbor all joins if the genid changed</li>
174 + * <li>We will refresh the neighbors timestamp</li>
175 + * </ul>
148 * 176 *
149 * @param ethPkt the Ethernet packet header 177 * @param ethPkt the Ethernet packet header
150 */ 178 */
...@@ -163,24 +191,61 @@ public class PIMInterface { ...@@ -163,24 +191,61 @@ public class PIMInterface {
163 return; 191 return;
164 } 192 }
165 193
166 - // TODO: Maybe a good idea to check the checksum. Let's jump into the hello options. 194 + // get the DR values for later calculation
167 - PIMHello hello = (PIMHello) pimhdr.getPayload(); 195 + PIMNeighbor dr = pimNeighbors.get(drIpaddress);
196 + checkNotNull(dr);
168 197
169 - // TODO: this is about where we find or create our PIMNeighbor 198 + IpAddress drip = drIpaddress;
199 + int drpri = dr.getPriority();
170 200
201 + // Assume we do not need to run a DR election
171 boolean reElectDr = false; 202 boolean reElectDr = false;
203 + boolean genidChanged = false;
172 204
173 - // Start walking through all the hello options to handle accordingly. 205 + PIMHello hello = (PIMHello) pimhdr.getPayload();
174 - for (PIMHelloOption opt : hello.getOptions().values()) { 206 +
207 + // Determine if we already have a PIMNeighbor
208 + PIMNeighbor nbr = pimNeighbors.getOrDefault(srcip, null);
209 + if (nbr == null) {
210 + nbr = new PIMNeighbor(srcip, hello.getOptions());
211 + checkNotNull(nbr);
212 + } else {
213 + Integer previousGenid = nbr.getGenid();
214 + nbr.addOptions(hello.getOptions());
215 + if (previousGenid != nbr.getGenid()) {
216 + genidChanged = true;
217 + }
218 + }
219 +
220 + // Refresh this neighbors timestamp
221 + nbr.refreshTimestamp();
222 +
223 + /*
224 + * the election method will frist determine if an election
225 + * needs to be run, if so it will run the election. The
226 + * IP address of the DR will be returned. If the IP address
227 + * of the DR is different from what we already have we know a
228 + * new DR has been elected.
229 + */
230 + IpAddress electedIp = election(nbr, drip, drpri);
231 + if (!drip.equals(electedIp)) {
232 + // we have a new DR.
233 + drIpaddress = electedIp;
234 + }
235 + }
175 236
176 - // TODO: This is where we handle the options and modify the neighbor accordingly. 237 + // Run an election if we need to. Return the elected IP address.
177 - // We'll need to create the PIMNeighbor class next. Depending on what happens 238 + private IpAddress election(PIMNeighbor nbr, IpAddress drip, int drpri) {
178 - // we may need to re-elect a DR 239 +
240 + IpAddress nbrip = nbr.getIpaddr();
241 + if (nbr.getPriority() > drpri) {
242 + return nbrip;
179 } 243 }
180 244
181 - if (reElectDr) { 245 + if (nbrip.compareTo(drip) > 0) {
182 - // TODO: create an election() method and call it here with a PIMNeighbor 246 + return nbrip;
183 } 247 }
248 + return drip;
184 } 249 }
185 250
186 /** 251 /**
...@@ -189,6 +254,6 @@ public class PIMInterface { ...@@ -189,6 +254,6 @@ public class PIMInterface {
189 * @param ethPkt the Ethernet packet header. 254 * @param ethPkt the Ethernet packet header.
190 */ 255 */
191 public void processJoinPrune(Ethernet ethPkt) { 256 public void processJoinPrune(Ethernet ethPkt) {
192 - 257 + // TODO: add Join/Prune processing code.
193 } 258 }
194 } 259 }
......
1 +/*
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 + */
16 +package org.onosproject.pim.impl;
17 +
18 +import org.onlab.packet.IpAddress;
19 +import org.onlab.packet.MacAddress;
20 +import org.onlab.packet.pim.PIMHelloOption;
21 +import org.slf4j.Logger;
22 +
23 +import java.nio.ByteBuffer;
24 +import java.util.Calendar;
25 +import java.util.Date;
26 +import java.util.Map;
27 +
28 +import static org.slf4j.LoggerFactory.getLogger;
29 +
30 +public class PIMNeighbor {
31 +
32 + private final Logger log = getLogger(getClass());
33 +
34 + // IP Address of this neighbor
35 + private IpAddress ipAddr;
36 +
37 + // MAC Address of the neighbor (Need for sending J/P)
38 + private MacAddress macAddr;
39 +
40 + // Hello Options
41 + // Our hello opt holdTime
42 + private short holdTime;
43 +
44 + // Our hello opt prune delay
45 + private int pruneDelay;
46 +
47 + // Neighbor priority
48 + private int priority;
49 +
50 + // Our current genId
51 + private int genId;
52 +
53 + // Our timestamp for this neighbor
54 + private Date lastRefresh;
55 +
56 + /**
57 + * Construct a new PIM Neighbor.
58 + *
59 + * @param ipAddr the IP Address of our new neighbor
60 + */
61 + public PIMNeighbor(IpAddress ipAddr, Map<Short, PIMHelloOption> opts) {
62 + this.ipAddr = ipAddr;
63 + this.addOptions(opts);
64 + }
65 +
66 + /**
67 + * Construct a new PIM neighbor.
68 + *
69 + * @param ipAddr the neighbors IP addr
70 + */
71 + public PIMNeighbor(IpAddress ipAddr, MacAddress macAddr) {
72 + this.ipAddr = ipAddr;
73 + this.macAddr = macAddr;
74 + }
75 +
76 + /**
77 + * Get the MAC address of this neighbor.
78 + *
79 + * @return the mac address
80 + */
81 + public MacAddress getMacaddr() {
82 + return macAddr;
83 + }
84 +
85 + /**
86 + * Get the IP Address of our neighbor.
87 + *
88 + * @return the IP address of our neighbor
89 + */
90 + public IpAddress getIpaddr() {
91 + return ipAddr;
92 + }
93 +
94 + /**
95 + * Set the IP address of our neighbor.
96 + *
97 + * @param ipAddr our neighbors IP address
98 + */
99 + public void setIpaddr(IpAddress ipAddr) {
100 + this.ipAddr = ipAddr;
101 + }
102 +
103 + /**
104 + * Get our neighbors holdTime.
105 + *
106 + * @return the holdTime
107 + */
108 + public short getHoldtime() {
109 + return holdTime;
110 + }
111 +
112 + /**
113 + * Set our neighbors holdTime.
114 + *
115 + * @param holdTime the holdTime
116 + */
117 + public void setHoldtime(short holdTime) {
118 + this.holdTime = holdTime;
119 + }
120 +
121 + /**
122 + * Get our neighbors prune delay.
123 + *
124 + * @return our neighbors prune delay
125 + */
126 + public int getPruneDelay() {
127 + return pruneDelay;
128 + }
129 +
130 + /**
131 + * Set our neighbors prune delay.
132 + *
133 + * @param pruneDelay the prune delay
134 + */
135 + public void setPruneDelay(int pruneDelay) {
136 + this.pruneDelay = pruneDelay;
137 + }
138 +
139 + /**
140 + * Get our neighbors priority.
141 + *
142 + * @return our neighbors priority
143 + */
144 + public int getPriority() {
145 + return priority;
146 + }
147 +
148 + /**
149 + * Set our neighbors priority.
150 + *
151 + * @param priority our neighbors priority
152 + */
153 + public void setPriority(int priority) {
154 + this.priority = priority;
155 + }
156 +
157 + /**
158 + * Get our neighbors Genid.
159 + *
160 + * @return our neighbor Genid
161 + */
162 + public int getGenid() {
163 + return genId;
164 + }
165 +
166 + /**
167 + * Set our neighbors GenId.
168 + *
169 + * @param genId our neighbors GenId
170 + */
171 + public void setGenid(int genId) {
172 + this.genId = genId;
173 + }
174 +
175 + /**
176 + * Add the options for this neighbor if needed.
177 + *
178 + * @param opts the options to be added/modified
179 + * @return true if options changed, false if no option has changed
180 + */
181 + public boolean addOptions(Map<Short, PIMHelloOption> opts) {
182 +
183 + boolean changed = false;
184 +
185 + for (PIMHelloOption opt : opts.values()) {
186 + Short otype = opt.getOptType();
187 + ByteBuffer val = ByteBuffer.wrap(opt.getValue());
188 +
189 + if (otype == PIMHelloOption.OPT_ADDRLIST) {
190 + // TODO: Will implement someday
191 + } else if (otype == PIMHelloOption.OPT_GENID) {
192 + int newval = val.getInt();
193 + if (newval != genId) {
194 + genId = newval;
195 + changed = true;
196 + }
197 + } else if (otype == PIMHelloOption.OPT_HOLDTIME) {
198 + short newval = val.getShort();
199 + if (newval != holdTime) {
200 + holdTime = newval;
201 + changed = true;
202 + }
203 + } else if (otype == PIMHelloOption.OPT_PRIORITY) {
204 + int newval = val.getInt();
205 + if (newval != priority) {
206 + priority = newval;
207 + changed = true;
208 + }
209 + } else if (otype == PIMHelloOption.OPT_PRUNEDELAY) {
210 + int newval = val.getInt();
211 + if (newval != pruneDelay) {
212 + pruneDelay = newval;
213 + changed = true;
214 + }
215 + } else {
216 + log.warn("received unknown pim hello options" + otype);
217 + }
218 + }
219 + return changed;
220 + }
221 +
222 + /**
223 + * Refresh this neighbors timestamp.
224 + */
225 + public void refreshTimestamp() {
226 + lastRefresh = Calendar.getInstance().getTime();
227 + }
228 +}