blob: f54b7b2bf4f065b7a0f2499e9aebce7b65d0c6cc [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 Eddy95421642015-10-21 17:22:13 -070020import org.onlab.packet.IpAddress;
21import org.onlab.packet.MacAddress;
22import org.onlab.packet.PIM;
23import org.onlab.packet.pim.PIMHello;
24import org.onlab.packet.pim.PIMHelloOption;
25import org.onosproject.incubator.net.intf.Interface;
Rusty Eddy95421642015-10-21 17:22:13 -070026import org.onosproject.net.host.InterfaceIpAddress;
27import org.slf4j.Logger;
Rusty Eddy95421642015-10-21 17:22:13 -070028
Rusty Eddy390498d2016-01-15 19:21:32 -080029import java.util.HashMap;
30import java.util.Map;
Rusty Eddy4ae5aa82015-12-15 12:58:27 -080031import java.util.Set;
Rusty Eddy95421642015-10-21 17:22:13 -070032
Rusty Eddy390498d2016-01-15 19:21:32 -080033import static com.google.common.base.Preconditions.checkNotNull;
Rusty Eddy4ae5aa82015-12-15 12:58:27 -080034import static org.slf4j.LoggerFactory.getLogger;
Rusty Eddy95421642015-10-21 17:22:13 -070035
36/**
Ray Milkeya059a702016-01-12 11:10:33 -080037 * PIM Interface represents an ONOS Interface with IP and MAC addresses for
Rusty Eddy4ae5aa82015-12-15 12:58:27 -080038 * a given ConnectPoint.
Rusty Eddy95421642015-10-21 17:22:13 -070039 */
40public class PIMInterface {
Rusty Eddy95421642015-10-21 17:22:13 -070041
Rusty Eddy4ae5aa82015-12-15 12:58:27 -080042 private final Logger log = getLogger(getClass());
Rusty Eddy95421642015-10-21 17:22:13 -070043
Rusty Eddy4ae5aa82015-12-15 12:58:27 -080044 private Interface onosInterface;
Rusty Eddy95421642015-10-21 17:22:13 -070045
Rusty Eddy4ae5aa82015-12-15 12:58:27 -080046 // Our hello opt holdtime
47 private short holdtime = PIMHelloOption.DEFAULT_HOLDTIME;
Rusty Eddy95421642015-10-21 17:22:13 -070048
Rusty Eddy4ae5aa82015-12-15 12:58:27 -080049 // Our hello opt prune delay
50 private int pruneDelay = PIMHelloOption.DEFAULT_PRUNEDELAY;
Rusty Eddy95421642015-10-21 17:22:13 -070051
Rusty Eddy4ae5aa82015-12-15 12:58:27 -080052 // Neighbor priority
53 private int priority = PIMHelloOption.DEFAULT_PRIORITY;
Rusty Eddy95421642015-10-21 17:22:13 -070054
Rusty Eddy4ae5aa82015-12-15 12:58:27 -080055 // Our current genid
56 private int genid = PIMHelloOption.DEFAULT_GENID; // Needs to be assigned.
Rusty Eddy95421642015-10-21 17:22:13 -070057
Rusty Eddy390498d2016-01-15 19:21:32 -080058 // 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
Rusty Eddy95421642015-10-21 17:22:13 -070064 /**
Rusty Eddy4ae5aa82015-12-15 12:58:27 -080065 * Create a PIMInterface from an ONOS Interface.
Charles Chan30ba4002015-11-05 14:45:16 -080066 *
Rusty Eddy4ae5aa82015-12-15 12:58:27 -080067 * @param intf the ONOS Interface.
Rusty Eddy95421642015-10-21 17:22:13 -070068 */
69 public PIMInterface(Interface intf) {
Rusty Eddy4ae5aa82015-12-15 12:58:27 -080070 onosInterface = intf;
Rusty Eddy390498d2016-01-15 19:21:32 -080071 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;
Rusty Eddy95421642015-10-21 17:22:13 -070082 }
83
84 /**
Rusty Eddy4ae5aa82015-12-15 12:58:27 -080085 * Return the ONOS Interface.
Rusty Eddy95421642015-10-21 17:22:13 -070086 *
Rusty Eddy4ae5aa82015-12-15 12:58:27 -080087 * @return ONOS Interface.
Rusty Eddy95421642015-10-21 17:22:13 -070088 */
89 public Interface getInterface() {
Rusty Eddy390498d2016-01-15 19:21:32 -080090 return onosInterface;
91
Rusty Eddy95421642015-10-21 17:22:13 -070092 }
93
94 /**
Rusty Eddy4ae5aa82015-12-15 12:58:27 -080095 * Set the ONOS Interface, it will override a previous value.
Rusty Eddy95421642015-10-21 17:22:13 -070096 *
Rusty Eddy4ae5aa82015-12-15 12:58:27 -080097 * @param intf ONOS Interface.
98 */
99 public PIMInterface setInterface(Interface intf) {
Rusty Eddy390498d2016-01-15 19:21:32 -0800100 onosInterface = intf;
Rusty Eddy4ae5aa82015-12-15 12:58:27 -0800101 return this;
102 }
103
104 /**
105 * Get the set of IP Addresses associated with this interface.
106 *
107 * @return a set of Ip Addresses on this interface
108 */
109 public Set<InterfaceIpAddress> getIpAddresses() {
Rusty Eddy390498d2016-01-15 19:21:32 -0800110 return onosInterface.ipAddresses();
Rusty Eddy4ae5aa82015-12-15 12:58:27 -0800111 }
112
113 /**
114 * Return a single "best" IP address.
115 *
116 * @return the choosen IP address or null if none
Rusty Eddy95421642015-10-21 17:22:13 -0700117 */
118 public IpAddress getIpAddress() {
Rusty Eddy4ae5aa82015-12-15 12:58:27 -0800119 if (onosInterface.ipAddresses().isEmpty()) {
Rusty Eddy95421642015-10-21 17:22:13 -0700120 return null;
121 }
122
Rusty Eddy95421642015-10-21 17:22:13 -0700123 IpAddress ipaddr = null;
Rusty Eddy4ae5aa82015-12-15 12:58:27 -0800124 for (InterfaceIpAddress ifipaddr : onosInterface.ipAddresses()) {
Rusty Eddy95421642015-10-21 17:22:13 -0700125 ipaddr = ifipaddr.ipAddress();
126 break;
127 }
128 return ipaddr;
129 }
130
131 /**
Rusty Eddy4ae5aa82015-12-15 12:58:27 -0800132 * Get the holdtime.
Rusty Eddy95421642015-10-21 17:22:13 -0700133 *
Rusty Eddy4ae5aa82015-12-15 12:58:27 -0800134 * @return the holdtime
135 */
136 public short getHoldtime() {
Rusty Eddy390498d2016-01-15 19:21:32 -0800137 return holdtime;
Rusty Eddy4ae5aa82015-12-15 12:58:27 -0800138 }
139
140 /**
141 * Get the prune delay.
142 *
143 * @return The prune delay
144 */
145 public int getPruneDelay() {
Rusty Eddy390498d2016-01-15 19:21:32 -0800146 return pruneDelay;
Rusty Eddy4ae5aa82015-12-15 12:58:27 -0800147 }
148
149 /**
150 * Get our hello priority.
151 *
152 * @return our priority
Rusty Eddy95421642015-10-21 17:22:13 -0700153 */
154 public int getPriority() {
Rusty Eddy390498d2016-01-15 19:21:32 -0800155 return priority;
Rusty Eddy95421642015-10-21 17:22:13 -0700156 }
157
158 /**
Rusty Eddy4ae5aa82015-12-15 12:58:27 -0800159 * Get our generation ID.
Rusty Eddy95421642015-10-21 17:22:13 -0700160 *
Rusty Eddy4ae5aa82015-12-15 12:58:27 -0800161 * @return our generation ID
Rusty Eddy95421642015-10-21 17:22:13 -0700162 */
Rusty Eddy4ae5aa82015-12-15 12:58:27 -0800163 public int getGenid() {
Rusty Eddy390498d2016-01-15 19:21:32 -0800164 return genid;
Rusty Eddy95421642015-10-21 17:22:13 -0700165 }
166
167 /**
Rusty Eddy390498d2016-01-15 19:21:32 -0800168 * 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>
Rusty Eddy95421642015-10-21 17:22:13 -0700176 *
Rusty Eddy4ae5aa82015-12-15 12:58:27 -0800177 * @param ethPkt the Ethernet packet header
Rusty Eddy95421642015-10-21 17:22:13 -0700178 */
Rusty Eddy4ae5aa82015-12-15 12:58:27 -0800179 public void processHello(Ethernet ethPkt) {
Rusty Eddy95421642015-10-21 17:22:13 -0700180
Rusty Eddy4ae5aa82015-12-15 12:58:27 -0800181 // We'll need to save our neighbors MAC address
182 MacAddress nbrmac = ethPkt.getSourceMAC();
Rusty Eddy95421642015-10-21 17:22:13 -0700183
Rusty Eddy4ae5aa82015-12-15 12:58:27 -0800184 // And we'll need to save neighbors IP Address.
185 IPv4 iphdr = (IPv4) ethPkt.getPayload();
186 IpAddress srcip = IpAddress.valueOf(iphdr.getSourceAddress());
Rusty Eddy95421642015-10-21 17:22:13 -0700187
Rusty Eddy4ae5aa82015-12-15 12:58:27 -0800188 PIM pimhdr = (PIM) iphdr.getPayload();
189 if (pimhdr.getPimMsgType() != PIM.TYPE_HELLO) {
190 log.error("process Hello has received a non hello packet type: " + pimhdr.getPimMsgType());
Rusty Eddy95421642015-10-21 17:22:13 -0700191 return;
192 }
193
Rusty Eddy390498d2016-01-15 19:21:32 -0800194 // get the DR values for later calculation
195 PIMNeighbor dr = pimNeighbors.get(drIpaddress);
196 checkNotNull(dr);
197
198 IpAddress drip = drIpaddress;
199 int drpri = dr.getPriority();
200
201 // Assume we do not need to run a DR election
202 boolean reElectDr = false;
203 boolean genidChanged = false;
204
Rusty Eddy4ae5aa82015-12-15 12:58:27 -0800205 PIMHello hello = (PIMHello) pimhdr.getPayload();
206
Rusty Eddy390498d2016-01-15 19:21:32 -0800207 // 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 }
Rusty Eddy95421642015-10-21 17:22:13 -0700218 }
Rusty Eddy4ae5aa82015-12-15 12:58:27 -0800219
Rusty Eddy390498d2016-01-15 19:21:32 -0800220 // 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;
Rusty Eddy4ae5aa82015-12-15 12:58:27 -0800234 }
Rusty Eddy95421642015-10-21 17:22:13 -0700235 }
236
Rusty Eddy390498d2016-01-15 19:21:32 -0800237 // Run an election if we need to. Return the elected IP address.
238 private IpAddress election(PIMNeighbor nbr, IpAddress drip, int drpri) {
239
240 IpAddress nbrip = nbr.getIpaddr();
241 if (nbr.getPriority() > drpri) {
242 return nbrip;
243 }
244
245 if (nbrip.compareTo(drip) > 0) {
246 return nbrip;
247 }
248 return drip;
249 }
250
Rusty Eddy95421642015-10-21 17:22:13 -0700251 /**
Rusty Eddy4ae5aa82015-12-15 12:58:27 -0800252 * Process an incoming PIM JoinPrune message.
Rusty Eddy95421642015-10-21 17:22:13 -0700253 *
Rusty Eddy4ae5aa82015-12-15 12:58:27 -0800254 * @param ethPkt the Ethernet packet header.
Rusty Eddy95421642015-10-21 17:22:13 -0700255 */
Rusty Eddy4ae5aa82015-12-15 12:58:27 -0800256 public void processJoinPrune(Ethernet ethPkt) {
Rusty Eddy390498d2016-01-15 19:21:32 -0800257 // TODO: add Join/Prune processing code.
Rusty Eddy95421642015-10-21 17:22:13 -0700258 }
Rusty Eddy95421642015-10-21 17:22:13 -0700259}