blob: b6ba703acc95d64387e8604fcf5bbf97db002493 [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;
Rusty Eddy4d5a92f2016-01-25 17:12:14 -080020import org.onlab.packet.Ip4Address;
Rusty Eddy95421642015-10-21 17:22:13 -070021import 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;
Rusty Eddy95421642015-10-21 17:22:13 -070027import org.onosproject.net.host.InterfaceIpAddress;
28import org.slf4j.Logger;
Rusty Eddy95421642015-10-21 17:22:13 -070029
Rusty Eddy390498d2016-01-15 19:21:32 -080030import java.util.HashMap;
31import java.util.Map;
Rusty Eddy4ae5aa82015-12-15 12:58:27 -080032import java.util.Set;
Rusty Eddy95421642015-10-21 17:22:13 -070033
Rusty Eddy390498d2016-01-15 19:21:32 -080034import static com.google.common.base.Preconditions.checkNotNull;
Rusty Eddy4ae5aa82015-12-15 12:58:27 -080035import static org.slf4j.LoggerFactory.getLogger;
Rusty Eddy95421642015-10-21 17:22:13 -070036
37/**
Ray Milkeya059a702016-01-12 11:10:33 -080038 * PIM Interface represents an ONOS Interface with IP and MAC addresses for
Rusty Eddy4ae5aa82015-12-15 12:58:27 -080039 * a given ConnectPoint.
Rusty Eddy95421642015-10-21 17:22:13 -070040 */
41public class PIMInterface {
Rusty Eddy95421642015-10-21 17:22:13 -070042
Rusty Eddy4ae5aa82015-12-15 12:58:27 -080043 private final Logger log = getLogger(getClass());
Rusty Eddy95421642015-10-21 17:22:13 -070044
Rusty Eddy4ae5aa82015-12-15 12:58:27 -080045 private Interface onosInterface;
Rusty Eddy95421642015-10-21 17:22:13 -070046
Rusty Eddy4ae5aa82015-12-15 12:58:27 -080047 // Our hello opt holdtime
48 private short holdtime = PIMHelloOption.DEFAULT_HOLDTIME;
Rusty Eddy95421642015-10-21 17:22:13 -070049
Rusty Eddy4ae5aa82015-12-15 12:58:27 -080050 // Our hello opt prune delay
51 private int pruneDelay = PIMHelloOption.DEFAULT_PRUNEDELAY;
Rusty Eddy95421642015-10-21 17:22:13 -070052
Rusty Eddy4ae5aa82015-12-15 12:58:27 -080053 // Neighbor priority
54 private int priority = PIMHelloOption.DEFAULT_PRIORITY;
Rusty Eddy95421642015-10-21 17:22:13 -070055
Rusty Eddy4ae5aa82015-12-15 12:58:27 -080056 // Our current genid
57 private int genid = PIMHelloOption.DEFAULT_GENID; // Needs to be assigned.
Rusty Eddy95421642015-10-21 17:22:13 -070058
Rusty Eddy390498d2016-01-15 19:21:32 -080059 // The IP address of the DR
60 IpAddress drIpaddress;
61
62 // A map of all our PIM neighbors keyed on our neighbors IP address
63 private Map<IpAddress, PIMNeighbor> pimNeighbors = new HashMap<>();
64
Rusty Eddy95421642015-10-21 17:22:13 -070065 /**
Rusty Eddy4ae5aa82015-12-15 12:58:27 -080066 * Create a PIMInterface from an ONOS Interface.
Charles Chan30ba4002015-11-05 14:45:16 -080067 *
Rusty Eddy4ae5aa82015-12-15 12:58:27 -080068 * @param intf the ONOS Interface.
Rusty Eddy95421642015-10-21 17:22:13 -070069 */
70 public PIMInterface(Interface intf) {
Rusty Eddy4ae5aa82015-12-15 12:58:27 -080071 onosInterface = intf;
Rusty Eddy390498d2016-01-15 19:21:32 -080072 IpAddress ourIp = getIpAddress();
73 MacAddress mac = intf.mac();
74
75 // Create a PIM Neighbor to represent ourselves for DR election.
76 PIMNeighbor us = new PIMNeighbor(ourIp, mac);
77
78 // Priority and IP address are all we need to DR election.
79 us.setPriority(priority);
80
81 pimNeighbors.put(ourIp, us);
82 drIpaddress = ourIp;
Rusty Eddy95421642015-10-21 17:22:13 -070083 }
84
85 /**
Rusty Eddy4ae5aa82015-12-15 12:58:27 -080086 * Return the ONOS Interface.
Rusty Eddy95421642015-10-21 17:22:13 -070087 *
Rusty Eddy4ae5aa82015-12-15 12:58:27 -080088 * @return ONOS Interface.
Rusty Eddy95421642015-10-21 17:22:13 -070089 */
90 public Interface getInterface() {
Rusty Eddy390498d2016-01-15 19:21:32 -080091 return onosInterface;
92
Rusty Eddy95421642015-10-21 17:22:13 -070093 }
94
95 /**
Rusty Eddy4ae5aa82015-12-15 12:58:27 -080096 * Set the ONOS Interface, it will override a previous value.
Rusty Eddy95421642015-10-21 17:22:13 -070097 *
Jian Lidfba7392016-01-22 16:46:58 -080098 * @param intf ONOS Interface
99 * @return PIM interface instance
Rusty Eddy4ae5aa82015-12-15 12:58:27 -0800100 */
101 public PIMInterface setInterface(Interface intf) {
Rusty Eddy390498d2016-01-15 19:21:32 -0800102 onosInterface = intf;
Rusty Eddy4ae5aa82015-12-15 12:58:27 -0800103 return this;
104 }
105
106 /**
107 * Get the set of IP Addresses associated with this interface.
108 *
109 * @return a set of Ip Addresses on this interface
110 */
111 public Set<InterfaceIpAddress> getIpAddresses() {
Rusty Eddy390498d2016-01-15 19:21:32 -0800112 return onosInterface.ipAddresses();
Rusty Eddy4ae5aa82015-12-15 12:58:27 -0800113 }
114
115 /**
116 * Return a single "best" IP address.
117 *
118 * @return the choosen IP address or null if none
Rusty Eddy95421642015-10-21 17:22:13 -0700119 */
120 public IpAddress getIpAddress() {
Rusty Eddy4ae5aa82015-12-15 12:58:27 -0800121 if (onosInterface.ipAddresses().isEmpty()) {
Rusty Eddy95421642015-10-21 17:22:13 -0700122 return null;
123 }
124
Rusty Eddy95421642015-10-21 17:22:13 -0700125 IpAddress ipaddr = null;
Rusty Eddy4ae5aa82015-12-15 12:58:27 -0800126 for (InterfaceIpAddress ifipaddr : onosInterface.ipAddresses()) {
Rusty Eddy95421642015-10-21 17:22:13 -0700127 ipaddr = ifipaddr.ipAddress();
128 break;
129 }
130 return ipaddr;
131 }
132
133 /**
Rusty Eddy4ae5aa82015-12-15 12:58:27 -0800134 * Get the holdtime.
Rusty Eddy95421642015-10-21 17:22:13 -0700135 *
Rusty Eddy4ae5aa82015-12-15 12:58:27 -0800136 * @return the holdtime
137 */
138 public short getHoldtime() {
Rusty Eddy390498d2016-01-15 19:21:32 -0800139 return holdtime;
Rusty Eddy4ae5aa82015-12-15 12:58:27 -0800140 }
141
142 /**
143 * Get the prune delay.
144 *
145 * @return The prune delay
146 */
147 public int getPruneDelay() {
Rusty Eddy390498d2016-01-15 19:21:32 -0800148 return pruneDelay;
Rusty Eddy4ae5aa82015-12-15 12:58:27 -0800149 }
150
151 /**
152 * Get our hello priority.
153 *
154 * @return our priority
Rusty Eddy95421642015-10-21 17:22:13 -0700155 */
156 public int getPriority() {
Rusty Eddy390498d2016-01-15 19:21:32 -0800157 return priority;
Rusty Eddy95421642015-10-21 17:22:13 -0700158 }
159
160 /**
Rusty Eddy4ae5aa82015-12-15 12:58:27 -0800161 * Get our generation ID.
Rusty Eddy95421642015-10-21 17:22:13 -0700162 *
Rusty Eddy4ae5aa82015-12-15 12:58:27 -0800163 * @return our generation ID
Rusty Eddy95421642015-10-21 17:22:13 -0700164 */
Rusty Eddy4ae5aa82015-12-15 12:58:27 -0800165 public int getGenid() {
Rusty Eddy390498d2016-01-15 19:21:32 -0800166 return genid;
Rusty Eddy95421642015-10-21 17:22:13 -0700167 }
168
169 /**
Rusty Eddy4d5a92f2016-01-25 17:12:14 -0800170 * Multicast a hello message out our interface. This hello message is sent
171 * periodically during the normal PIM Neighbor refresh time, as well as a
172 * result of a newly created interface.
173 */
174 public void sendHello() {
175
176 // Create the base PIM Packet and mark it a hello packet
177 PIMPacket pimPacket = new PIMPacket(PIM.TYPE_HELLO);
178
179 // We need to set the source MAC and IPv4 addresses
180 pimPacket.setSrcMacAddr(onosInterface.mac());
181 pimPacket.setSrcIpAddress(Ip4Address.valueOf(getIpAddress().toOctets()));
182
183 // Create the hello message with options
184 PIMHello hello = new PIMHello();
185 hello.createDefaultOptions();
186
187 // Now set the hello option payload
188 pimPacket.setPIMPayload(hello);
189
190 // TODO: How to send the packet.?.
191 }
192
193 /**
Rusty Eddy390498d2016-01-15 19:21:32 -0800194 * Process an incoming PIM Hello message. There are a few things going on in
195 * this method:
196 * <ul>
197 * <li>We <em>may</em> have to create a new neighbor if one does not already exist</li>
198 * <li>We <em>may</em> need to re-elect a new DR if new information is received</li>
199 * <li>We <em>may</em> need to send an existing neighbor all joins if the genid changed</li>
200 * <li>We will refresh the neighbors timestamp</li>
201 * </ul>
Rusty Eddy95421642015-10-21 17:22:13 -0700202 *
Rusty Eddy4ae5aa82015-12-15 12:58:27 -0800203 * @param ethPkt the Ethernet packet header
Rusty Eddy95421642015-10-21 17:22:13 -0700204 */
Rusty Eddy4ae5aa82015-12-15 12:58:27 -0800205 public void processHello(Ethernet ethPkt) {
Rusty Eddy95421642015-10-21 17:22:13 -0700206
Rusty Eddy4ae5aa82015-12-15 12:58:27 -0800207 // We'll need to save our neighbors MAC address
208 MacAddress nbrmac = ethPkt.getSourceMAC();
Rusty Eddy95421642015-10-21 17:22:13 -0700209
Rusty Eddy4ae5aa82015-12-15 12:58:27 -0800210 // And we'll need to save neighbors IP Address.
211 IPv4 iphdr = (IPv4) ethPkt.getPayload();
212 IpAddress srcip = IpAddress.valueOf(iphdr.getSourceAddress());
Rusty Eddy95421642015-10-21 17:22:13 -0700213
Rusty Eddy4ae5aa82015-12-15 12:58:27 -0800214 PIM pimhdr = (PIM) iphdr.getPayload();
215 if (pimhdr.getPimMsgType() != PIM.TYPE_HELLO) {
216 log.error("process Hello has received a non hello packet type: " + pimhdr.getPimMsgType());
Rusty Eddy95421642015-10-21 17:22:13 -0700217 return;
218 }
219
Rusty Eddy390498d2016-01-15 19:21:32 -0800220 // get the DR values for later calculation
221 PIMNeighbor dr = pimNeighbors.get(drIpaddress);
222 checkNotNull(dr);
223
224 IpAddress drip = drIpaddress;
225 int drpri = dr.getPriority();
226
227 // Assume we do not need to run a DR election
228 boolean reElectDr = false;
229 boolean genidChanged = false;
230
Rusty Eddy4ae5aa82015-12-15 12:58:27 -0800231 PIMHello hello = (PIMHello) pimhdr.getPayload();
232
Rusty Eddy390498d2016-01-15 19:21:32 -0800233 // Determine if we already have a PIMNeighbor
234 PIMNeighbor nbr = pimNeighbors.getOrDefault(srcip, null);
235 if (nbr == null) {
236 nbr = new PIMNeighbor(srcip, hello.getOptions());
237 checkNotNull(nbr);
238 } else {
239 Integer previousGenid = nbr.getGenid();
240 nbr.addOptions(hello.getOptions());
241 if (previousGenid != nbr.getGenid()) {
242 genidChanged = true;
243 }
Rusty Eddy95421642015-10-21 17:22:13 -0700244 }
Rusty Eddy4ae5aa82015-12-15 12:58:27 -0800245
Rusty Eddy390498d2016-01-15 19:21:32 -0800246 // Refresh this neighbors timestamp
247 nbr.refreshTimestamp();
248
249 /*
250 * the election method will frist determine if an election
251 * needs to be run, if so it will run the election. The
252 * IP address of the DR will be returned. If the IP address
253 * of the DR is different from what we already have we know a
254 * new DR has been elected.
255 */
256 IpAddress electedIp = election(nbr, drip, drpri);
257 if (!drip.equals(electedIp)) {
258 // we have a new DR.
259 drIpaddress = electedIp;
Rusty Eddy4ae5aa82015-12-15 12:58:27 -0800260 }
Rusty Eddy95421642015-10-21 17:22:13 -0700261 }
262
Rusty Eddy390498d2016-01-15 19:21:32 -0800263 // Run an election if we need to. Return the elected IP address.
264 private IpAddress election(PIMNeighbor nbr, IpAddress drip, int drpri) {
265
266 IpAddress nbrip = nbr.getIpaddr();
267 if (nbr.getPriority() > drpri) {
268 return nbrip;
269 }
270
271 if (nbrip.compareTo(drip) > 0) {
272 return nbrip;
273 }
274 return drip;
275 }
276
Rusty Eddy95421642015-10-21 17:22:13 -0700277 /**
Rusty Eddy4ae5aa82015-12-15 12:58:27 -0800278 * Process an incoming PIM JoinPrune message.
Rusty Eddy95421642015-10-21 17:22:13 -0700279 *
Rusty Eddy4ae5aa82015-12-15 12:58:27 -0800280 * @param ethPkt the Ethernet packet header.
Rusty Eddy95421642015-10-21 17:22:13 -0700281 */
Rusty Eddy4ae5aa82015-12-15 12:58:27 -0800282 public void processJoinPrune(Ethernet ethPkt) {
Rusty Eddy390498d2016-01-15 19:21:32 -0800283 // TODO: add Join/Prune processing code.
Rusty Eddy95421642015-10-21 17:22:13 -0700284 }
Rusty Eddy95421642015-10-21 17:22:13 -0700285}