blob: c4d35fcd0f215dd0192985f244186d72dde522fb [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 *
Jian Lidfba7392016-01-22 16:46:58 -080097 * @param intf ONOS Interface
98 * @return PIM interface instance
Rusty Eddy4ae5aa82015-12-15 12:58:27 -080099 */
100 public PIMInterface setInterface(Interface intf) {
Rusty Eddy390498d2016-01-15 19:21:32 -0800101 onosInterface = intf;
Rusty Eddy4ae5aa82015-12-15 12:58:27 -0800102 return this;
103 }
104
105 /**
106 * Get the set of IP Addresses associated with this interface.
107 *
108 * @return a set of Ip Addresses on this interface
109 */
110 public Set<InterfaceIpAddress> getIpAddresses() {
Rusty Eddy390498d2016-01-15 19:21:32 -0800111 return onosInterface.ipAddresses();
Rusty Eddy4ae5aa82015-12-15 12:58:27 -0800112 }
113
114 /**
115 * Return a single "best" IP address.
116 *
117 * @return the choosen IP address or null if none
Rusty Eddy95421642015-10-21 17:22:13 -0700118 */
119 public IpAddress getIpAddress() {
Rusty Eddy4ae5aa82015-12-15 12:58:27 -0800120 if (onosInterface.ipAddresses().isEmpty()) {
Rusty Eddy95421642015-10-21 17:22:13 -0700121 return null;
122 }
123
Rusty Eddy95421642015-10-21 17:22:13 -0700124 IpAddress ipaddr = null;
Rusty Eddy4ae5aa82015-12-15 12:58:27 -0800125 for (InterfaceIpAddress ifipaddr : onosInterface.ipAddresses()) {
Rusty Eddy95421642015-10-21 17:22:13 -0700126 ipaddr = ifipaddr.ipAddress();
127 break;
128 }
129 return ipaddr;
130 }
131
132 /**
Rusty Eddy4ae5aa82015-12-15 12:58:27 -0800133 * Get the holdtime.
Rusty Eddy95421642015-10-21 17:22:13 -0700134 *
Rusty Eddy4ae5aa82015-12-15 12:58:27 -0800135 * @return the holdtime
136 */
137 public short getHoldtime() {
Rusty Eddy390498d2016-01-15 19:21:32 -0800138 return holdtime;
Rusty Eddy4ae5aa82015-12-15 12:58:27 -0800139 }
140
141 /**
142 * Get the prune delay.
143 *
144 * @return The prune delay
145 */
146 public int getPruneDelay() {
Rusty Eddy390498d2016-01-15 19:21:32 -0800147 return pruneDelay;
Rusty Eddy4ae5aa82015-12-15 12:58:27 -0800148 }
149
150 /**
151 * Get our hello priority.
152 *
153 * @return our priority
Rusty Eddy95421642015-10-21 17:22:13 -0700154 */
155 public int getPriority() {
Rusty Eddy390498d2016-01-15 19:21:32 -0800156 return priority;
Rusty Eddy95421642015-10-21 17:22:13 -0700157 }
158
159 /**
Rusty Eddy4ae5aa82015-12-15 12:58:27 -0800160 * Get our generation ID.
Rusty Eddy95421642015-10-21 17:22:13 -0700161 *
Rusty Eddy4ae5aa82015-12-15 12:58:27 -0800162 * @return our generation ID
Rusty Eddy95421642015-10-21 17:22:13 -0700163 */
Rusty Eddy4ae5aa82015-12-15 12:58:27 -0800164 public int getGenid() {
Rusty Eddy390498d2016-01-15 19:21:32 -0800165 return genid;
Rusty Eddy95421642015-10-21 17:22:13 -0700166 }
167
168 /**
Rusty Eddy390498d2016-01-15 19:21:32 -0800169 * Process an incoming PIM Hello message. There are a few things going on in
170 * this method:
171 * <ul>
172 * <li>We <em>may</em> have to create a new neighbor if one does not already exist</li>
173 * <li>We <em>may</em> need to re-elect a new DR if new information is received</li>
174 * <li>We <em>may</em> need to send an existing neighbor all joins if the genid changed</li>
175 * <li>We will refresh the neighbors timestamp</li>
176 * </ul>
Rusty Eddy95421642015-10-21 17:22:13 -0700177 *
Rusty Eddy4ae5aa82015-12-15 12:58:27 -0800178 * @param ethPkt the Ethernet packet header
Rusty Eddy95421642015-10-21 17:22:13 -0700179 */
Rusty Eddy4ae5aa82015-12-15 12:58:27 -0800180 public void processHello(Ethernet ethPkt) {
Rusty Eddy95421642015-10-21 17:22:13 -0700181
Rusty Eddy4ae5aa82015-12-15 12:58:27 -0800182 // We'll need to save our neighbors MAC address
183 MacAddress nbrmac = ethPkt.getSourceMAC();
Rusty Eddy95421642015-10-21 17:22:13 -0700184
Rusty Eddy4ae5aa82015-12-15 12:58:27 -0800185 // And we'll need to save neighbors IP Address.
186 IPv4 iphdr = (IPv4) ethPkt.getPayload();
187 IpAddress srcip = IpAddress.valueOf(iphdr.getSourceAddress());
Rusty Eddy95421642015-10-21 17:22:13 -0700188
Rusty Eddy4ae5aa82015-12-15 12:58:27 -0800189 PIM pimhdr = (PIM) iphdr.getPayload();
190 if (pimhdr.getPimMsgType() != PIM.TYPE_HELLO) {
191 log.error("process Hello has received a non hello packet type: " + pimhdr.getPimMsgType());
Rusty Eddy95421642015-10-21 17:22:13 -0700192 return;
193 }
194
Rusty Eddy390498d2016-01-15 19:21:32 -0800195 // get the DR values for later calculation
196 PIMNeighbor dr = pimNeighbors.get(drIpaddress);
197 checkNotNull(dr);
198
199 IpAddress drip = drIpaddress;
200 int drpri = dr.getPriority();
201
202 // Assume we do not need to run a DR election
203 boolean reElectDr = false;
204 boolean genidChanged = false;
205
Rusty Eddy4ae5aa82015-12-15 12:58:27 -0800206 PIMHello hello = (PIMHello) pimhdr.getPayload();
207
Rusty Eddy390498d2016-01-15 19:21:32 -0800208 // Determine if we already have a PIMNeighbor
209 PIMNeighbor nbr = pimNeighbors.getOrDefault(srcip, null);
210 if (nbr == null) {
211 nbr = new PIMNeighbor(srcip, hello.getOptions());
212 checkNotNull(nbr);
213 } else {
214 Integer previousGenid = nbr.getGenid();
215 nbr.addOptions(hello.getOptions());
216 if (previousGenid != nbr.getGenid()) {
217 genidChanged = true;
218 }
Rusty Eddy95421642015-10-21 17:22:13 -0700219 }
Rusty Eddy4ae5aa82015-12-15 12:58:27 -0800220
Rusty Eddy390498d2016-01-15 19:21:32 -0800221 // Refresh this neighbors timestamp
222 nbr.refreshTimestamp();
223
224 /*
225 * the election method will frist determine if an election
226 * needs to be run, if so it will run the election. The
227 * IP address of the DR will be returned. If the IP address
228 * of the DR is different from what we already have we know a
229 * new DR has been elected.
230 */
231 IpAddress electedIp = election(nbr, drip, drpri);
232 if (!drip.equals(electedIp)) {
233 // we have a new DR.
234 drIpaddress = electedIp;
Rusty Eddy4ae5aa82015-12-15 12:58:27 -0800235 }
Rusty Eddy95421642015-10-21 17:22:13 -0700236 }
237
Rusty Eddy390498d2016-01-15 19:21:32 -0800238 // Run an election if we need to. Return the elected IP address.
239 private IpAddress election(PIMNeighbor nbr, IpAddress drip, int drpri) {
240
241 IpAddress nbrip = nbr.getIpaddr();
242 if (nbr.getPriority() > drpri) {
243 return nbrip;
244 }
245
246 if (nbrip.compareTo(drip) > 0) {
247 return nbrip;
248 }
249 return drip;
250 }
251
Rusty Eddy95421642015-10-21 17:22:13 -0700252 /**
Rusty Eddy4ae5aa82015-12-15 12:58:27 -0800253 * Process an incoming PIM JoinPrune message.
Rusty Eddy95421642015-10-21 17:22:13 -0700254 *
Rusty Eddy4ae5aa82015-12-15 12:58:27 -0800255 * @param ethPkt the Ethernet packet header.
Rusty Eddy95421642015-10-21 17:22:13 -0700256 */
Rusty Eddy4ae5aa82015-12-15 12:58:27 -0800257 public void processJoinPrune(Ethernet ethPkt) {
Rusty Eddy390498d2016-01-15 19:21:32 -0800258 // TODO: add Join/Prune processing code.
Rusty Eddy95421642015-10-21 17:22:13 -0700259 }
Rusty Eddy95421642015-10-21 17:22:13 -0700260}