Committed by
Gerrit Code Review
PIM Neighbors refactored to PIMInterfaces and now used
the NetworkConfiguration service Change-Id: Ieb0a6faee3f3399f1bba5d9614fce6b0050e8510
Showing
9 changed files
with
906 additions
and
151 deletions
... | @@ -18,30 +18,30 @@ package org.onosproject.pim.cli; | ... | @@ -18,30 +18,30 @@ package org.onosproject.pim.cli; |
18 | import com.fasterxml.jackson.databind.JsonNode; | 18 | import com.fasterxml.jackson.databind.JsonNode; |
19 | import org.apache.karaf.shell.commands.Command; | 19 | import org.apache.karaf.shell.commands.Command; |
20 | import org.onosproject.cli.AbstractShellCommand; | 20 | import org.onosproject.cli.AbstractShellCommand; |
21 | -import org.onosproject.net.ConnectPoint; | 21 | +import org.onosproject.pim.impl.PIMInterface; |
22 | -import org.onosproject.pim.impl.PIMNeighbors; | 22 | +import org.onosproject.pim.impl.PIMInterfaces; |
23 | -import org.onosproject.pim.impl.PIMNeighborsCodec; | 23 | +import org.onosproject.pim.impl.PIMInterfacesCodec; |
24 | 24 | ||
25 | -import java.util.HashMap; | 25 | +import java.util.Collection; |
26 | 26 | ||
27 | -@Command(scope = "onos", name = "pim-neighbors", description = "Displays the pim neighbors") | 27 | +@Command(scope = "onos", name = "pim-interfaces", description = "Displays the pim interfaces") |
28 | public class PIMShowCommand extends AbstractShellCommand { | 28 | public class PIMShowCommand extends AbstractShellCommand { |
29 | 29 | ||
30 | // prints either the json or cli version of the hash map connect point | 30 | // prints either the json or cli version of the hash map connect point |
31 | - // neighbors from the PIMNeighbors class. | 31 | + // neighbors from the PIMInterfaces class. |
32 | @Override | 32 | @Override |
33 | protected void execute() { | 33 | protected void execute() { |
34 | // grab connect point neighbors hash map to send in to json encoder. | 34 | // grab connect point neighbors hash map to send in to json encoder. |
35 | - HashMap<ConnectPoint, PIMNeighbors> pimNbrs = PIMNeighbors.getConnectPointNeighbors(); | 35 | + Collection<PIMInterface> pimIntfs = PIMInterfaces.getInstance().getInterfaces(); |
36 | if (outputJson()) { | 36 | if (outputJson()) { |
37 | - print("%s", json(pimNbrs)); | 37 | + print("%s", json(pimIntfs)); |
38 | } else { | 38 | } else { |
39 | - print(PIMNeighbors.printPimNeighbors()); | 39 | + print(PIMInterfaces.getInstance().printInterfaces()); |
40 | } | 40 | } |
41 | } | 41 | } |
42 | 42 | ||
43 | - private JsonNode json(HashMap<ConnectPoint, PIMNeighbors> pimNbrs) { | 43 | + private JsonNode json(Collection<PIMInterface> pimIntfs) { |
44 | - return new PIMNeighborsCodec().encode(pimNbrs, this); | 44 | + return new PIMInterfacesCodec().encode(pimIntfs, this); |
45 | } | 45 | } |
46 | 46 | ||
47 | } | 47 | } |
... | \ No newline at end of file | ... | \ No newline at end of file | ... | ... |
... | @@ -22,132 +22,61 @@ import org.apache.felix.scr.annotations.Component; | ... | @@ -22,132 +22,61 @@ import org.apache.felix.scr.annotations.Component; |
22 | import org.apache.felix.scr.annotations.Deactivate; | 22 | import org.apache.felix.scr.annotations.Deactivate; |
23 | import org.apache.felix.scr.annotations.Reference; | 23 | import org.apache.felix.scr.annotations.Reference; |
24 | import org.apache.felix.scr.annotations.ReferenceCardinality; | 24 | import org.apache.felix.scr.annotations.ReferenceCardinality; |
25 | -import org.onlab.packet.Ethernet; | ||
26 | -import org.onlab.packet.IPv4; | ||
27 | -import org.onlab.packet.Ip4Address; | ||
28 | -import org.onlab.packet.IpAddress; | ||
29 | -import org.onlab.packet.IpPrefix; | ||
30 | -import org.onlab.packet.PIM; | ||
31 | import org.onosproject.core.ApplicationId; | 25 | import org.onosproject.core.ApplicationId; |
32 | import org.onosproject.core.CoreService; | 26 | import org.onosproject.core.CoreService; |
33 | -import org.onosproject.net.flow.DefaultTrafficSelector; | 27 | +import org.onosproject.incubator.net.intf.InterfaceService; |
34 | -import org.onosproject.net.flow.TrafficSelector; | 28 | +import org.onosproject.net.config.NetworkConfigService; |
35 | -import org.onosproject.net.packet.InboundPacket; | ||
36 | -import org.onosproject.net.packet.PacketContext; | ||
37 | -import org.onosproject.net.packet.PacketPriority; | ||
38 | -import org.onosproject.net.packet.PacketProcessor; | ||
39 | import org.onosproject.net.packet.PacketService; | 29 | import org.onosproject.net.packet.PacketService; |
40 | import org.slf4j.Logger; | 30 | import org.slf4j.Logger; |
41 | 31 | ||
42 | /** | 32 | /** |
43 | - * Protocol Independent Multicast Emulation. | 33 | + * Protocol Independent Multicast (PIM) Emulation. This component is responsible |
34 | + * for reference the services this PIM module is going to need, then initializing | ||
35 | + * the corresponding utility classes. | ||
44 | */ | 36 | */ |
45 | @Component(immediate = true) | 37 | @Component(immediate = true) |
46 | public class PIMComponent { | 38 | public class PIMComponent { |
47 | private final Logger log = getLogger(getClass()); | 39 | private final Logger log = getLogger(getClass()); |
48 | 40 | ||
41 | + // Register to receive PIM packets, used to send packets as well | ||
49 | @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) | 42 | @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) |
50 | protected PacketService packetService; | 43 | protected PacketService packetService; |
51 | 44 | ||
45 | + // Get the appId | ||
52 | @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) | 46 | @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) |
53 | protected CoreService coreService; | 47 | protected CoreService coreService; |
54 | 48 | ||
55 | - private PIMPacketProcessor processor = new PIMPacketProcessor(); | 49 | + // Get the network configuration updates |
50 | + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) | ||
51 | + protected NetworkConfigService configService; | ||
52 | + | ||
53 | + // Access defined network (IP) interfaces | ||
54 | + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) | ||
55 | + protected InterfaceService interfaceService; | ||
56 | + | ||
56 | private static ApplicationId appId; | 57 | private static ApplicationId appId; |
57 | 58 | ||
59 | + private PIMInterfaces pimInterfaces; | ||
60 | + private PIMPacketHandler pimPacketHandler; | ||
61 | + | ||
58 | @Activate | 62 | @Activate |
59 | public void activate() { | 63 | public void activate() { |
60 | appId = coreService.registerApplication("org.onosproject.pim"); | 64 | appId = coreService.registerApplication("org.onosproject.pim"); |
61 | 65 | ||
62 | - packetService.addProcessor(processor, PacketProcessor.director(1)); | 66 | + // Initialize the Packet Handler class |
67 | + pimPacketHandler = PIMPacketHandler.getInstance(); | ||
68 | + pimPacketHandler.initialize(packetService, appId); | ||
63 | 69 | ||
64 | - // Build a traffic selector for all multicast traffic | 70 | + // Initialize the Interface class |
65 | - TrafficSelector.Builder selector = DefaultTrafficSelector.builder(); | 71 | + pimInterfaces = PIMInterfaces.getInstance(); |
66 | - selector.matchEthType(Ethernet.TYPE_IPV4); | 72 | + pimInterfaces.initialize(configService, interfaceService); |
67 | - selector.matchIPProtocol(IPv4.PROTOCOL_PIM); | ||
68 | - packetService.requestPackets(selector.build(), PacketPriority.REACTIVE, appId); | ||
69 | 73 | ||
70 | log.info("Started"); | 74 | log.info("Started"); |
71 | } | 75 | } |
72 | 76 | ||
73 | @Deactivate | 77 | @Deactivate |
74 | public void deactivate() { | 78 | public void deactivate() { |
75 | - packetService.removeProcessor(processor); | 79 | + PIMPacketHandler.getInstance().stop(); |
76 | - processor = null; | ||
77 | log.info("Stopped"); | 80 | log.info("Stopped"); |
78 | } | 81 | } |
79 | - | ||
80 | - /** | ||
81 | - * Packet processor responsible for handling IGMP packets. | ||
82 | - */ | ||
83 | - private class PIMPacketProcessor implements PacketProcessor { | ||
84 | - | ||
85 | - @Override | ||
86 | - public void process(PacketContext context) { | ||
87 | - // Stop processing if the packet has been handled, since we | ||
88 | - // can't do any more to it. | ||
89 | - if (context.isHandled()) { | ||
90 | - return; | ||
91 | - } | ||
92 | - | ||
93 | - InboundPacket pkt = context.inPacket(); | ||
94 | - if (pkt == null) { | ||
95 | - return; | ||
96 | - } | ||
97 | - | ||
98 | - Ethernet ethPkt = pkt.parsed(); | ||
99 | - if (ethPkt == null) { | ||
100 | - return; | ||
101 | - } | ||
102 | - | ||
103 | - /* | ||
104 | - * IPv6 MLD packets are handled by ICMP6. We'll only deal | ||
105 | - * with IPv4. | ||
106 | - */ | ||
107 | - if (ethPkt.getEtherType() != Ethernet.TYPE_IPV4) { | ||
108 | - return; | ||
109 | - } | ||
110 | - | ||
111 | - IPv4 ip = (IPv4) ethPkt.getPayload(); | ||
112 | - IpAddress gaddr = IpAddress.valueOf(ip.getDestinationAddress()); | ||
113 | - IpAddress saddr = Ip4Address.valueOf(ip.getSourceAddress()); | ||
114 | - log.debug("Packet (" + saddr.toString() + ", " + gaddr.toString() + | ||
115 | - "\tingress port: " + context.inPacket().receivedFrom().toString()); | ||
116 | - | ||
117 | - if (ip.getProtocol() != IPv4.PROTOCOL_PIM) { | ||
118 | - log.debug("PIM Picked up a non PIM packet: IP protocol: " + ip.getProtocol()); | ||
119 | - return; | ||
120 | - } | ||
121 | - | ||
122 | - // TODO: check incoming to be PIM.PIM_ADDRESS or "Our" address. | ||
123 | - IpPrefix spfx = IpPrefix.valueOf(saddr, 32); | ||
124 | - IpPrefix gpfx = IpPrefix.valueOf(gaddr, 32); | ||
125 | - | ||
126 | - PIM pim = (PIM) ip.getPayload(); | ||
127 | - switch (pim.getPimMsgType()) { | ||
128 | - | ||
129 | - case PIM.TYPE_HELLO: | ||
130 | - PIMNeighbors.processHello(ethPkt, context.inPacket().receivedFrom()); | ||
131 | - break; | ||
132 | - | ||
133 | - case PIM.TYPE_JOIN_PRUNE_REQUEST: | ||
134 | - // Create the function | ||
135 | - break; | ||
136 | - | ||
137 | - case PIM.TYPE_ASSERT: | ||
138 | - case PIM.TYPE_BOOTSTRAP: | ||
139 | - case PIM.TYPE_CANDIDATE_RP_ADV: | ||
140 | - case PIM.TYPE_GRAFT: | ||
141 | - case PIM.TYPE_GRAFT_ACK: | ||
142 | - case PIM.TYPE_REGISTER: | ||
143 | - case PIM.TYPE_REGISTER_STOP: | ||
144 | - log.debug("Unsupported PIM message type: " + pim.getPimMsgType()); | ||
145 | - break; | ||
146 | - | ||
147 | - default: | ||
148 | - log.debug("Unkown PIM message type: " + pim.getPimMsgType()); | ||
149 | - break; | ||
150 | - } | ||
151 | - } | ||
152 | - } | ||
153 | } | 82 | } | ... | ... |
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.Ethernet; | ||
19 | +import org.onlab.packet.IPv4; | ||
20 | +import org.onlab.packet.Ip4Address; | ||
21 | +import org.onlab.packet.IpAddress; | ||
22 | +import org.onlab.packet.MacAddress; | ||
23 | +import org.onlab.packet.PIM; | ||
24 | +import org.onlab.packet.pim.PIMHello; | ||
25 | +import org.onlab.packet.pim.PIMHelloOption; | ||
26 | +import org.onosproject.incubator.net.intf.Interface; | ||
27 | +import org.onosproject.net.ConnectPoint; | ||
28 | +import org.onosproject.net.host.InterfaceIpAddress; | ||
29 | +import org.slf4j.Logger; | ||
30 | +import org.slf4j.LoggerFactory; | ||
31 | + | ||
32 | +import java.util.Collection; | ||
33 | +import java.util.HashMap; | ||
34 | +import java.util.Map; | ||
35 | + | ||
36 | +import 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 | + */ | ||
42 | +public 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. | ||
68 | + */ | ||
69 | + public PIMInterface(Interface intf) { | ||
70 | + | ||
71 | + log.debug("Adding an interface: " + intf.toString() + "\n"); | ||
72 | + this.theInterface = intf; | ||
73 | + | ||
74 | + // Send a hello to let our neighbors know we are alive | ||
75 | + sendHello(); | ||
76 | + } | ||
77 | + | ||
78 | + /** | ||
79 | + * Get the PIM Interface. | ||
80 | + * | ||
81 | + * @return the PIM Interface | ||
82 | + */ | ||
83 | + public Interface getInterface() { | ||
84 | + return theInterface; | ||
85 | + } | ||
86 | + | ||
87 | + /** | ||
88 | + * Getter for our IP address. | ||
89 | + * | ||
90 | + * @return our IP address. | ||
91 | + */ | ||
92 | + public IpAddress getIpAddress() { | ||
93 | + if (theInterface.ipAddresses().isEmpty()) { | ||
94 | + return null; | ||
95 | + } | ||
96 | + | ||
97 | + // We will just assume the first interface on the list | ||
98 | + IpAddress ipaddr = null; | ||
99 | + for (InterfaceIpAddress ifipaddr : theInterface.ipAddresses()) { | ||
100 | + ipaddr = ifipaddr.ipAddress(); | ||
101 | + break; | ||
102 | + } | ||
103 | + return ipaddr; | ||
104 | + } | ||
105 | + | ||
106 | + /** | ||
107 | + * Get our priority. | ||
108 | + * | ||
109 | + * @return our priority. | ||
110 | + */ | ||
111 | + public int getPriority() { | ||
112 | + return this.priority; | ||
113 | + } | ||
114 | + | ||
115 | + /** | ||
116 | + * Get the designated router on this connection. | ||
117 | + * | ||
118 | + * @return the PIMNeighbor representing the DR | ||
119 | + */ | ||
120 | + public PIMNeighbor getDesignatedRouter() { | ||
121 | + return designatedRouter; | ||
122 | + } | ||
123 | + | ||
124 | + /** | ||
125 | + * Are we the DR on this CP? | ||
126 | + * | ||
127 | + * @return true if we are, false if not | ||
128 | + */ | ||
129 | + public boolean areWeDr() { | ||
130 | + return (designatedRouter != null && | ||
131 | + designatedRouter.getPrimaryAddr().equals(this.getIpAddress())); | ||
132 | + } | ||
133 | + | ||
134 | + /** | ||
135 | + * Return a collection of PIM Neighbors. | ||
136 | + * | ||
137 | + * @return the collection of PIM Neighbors | ||
138 | + */ | ||
139 | + public Collection<PIMNeighbor> getNeighbors() { | ||
140 | + return this.neighbors.values(); | ||
141 | + } | ||
142 | + | ||
143 | + /** | ||
144 | + * Find the neighbor with the given IP address on this CP. | ||
145 | + * | ||
146 | + * @param ipaddr the IP address of the neighbor we are interested in | ||
147 | + * @return the pim neighbor if it exists | ||
148 | + */ | ||
149 | + public PIMNeighbor findNeighbor(IpAddress ipaddr) { | ||
150 | + PIMNeighbor nbr = neighbors.get(ipaddr); | ||
151 | + return nbr; | ||
152 | + } | ||
153 | + | ||
154 | + /** | ||
155 | + * Add a new PIM neighbor to this list. | ||
156 | + * | ||
157 | + * @param nbr the neighbor to be added. | ||
158 | + */ | ||
159 | + public void addNeighbor(PIMNeighbor nbr) { | ||
160 | + if (neighbors.containsKey(nbr.getPrimaryAddr())) { | ||
161 | + | ||
162 | + log.debug("We are adding a neighbor that already exists: {}", nbr.toString()); | ||
163 | + neighbors.remove(nbr.getPrimaryAddr()); | ||
164 | + } | ||
165 | + neighbors.put(nbr.getPrimaryAddr(), nbr); | ||
166 | + } | ||
167 | + | ||
168 | + /** | ||
169 | + * Remove the neighbor from our neighbor list. | ||
170 | + * | ||
171 | + * @param ipaddr the IP address of the neighbor to remove | ||
172 | + */ | ||
173 | + public void removeNeighbor(IpAddress ipaddr) { | ||
174 | + | ||
175 | + if (neighbors.containsKey(ipaddr)) { | ||
176 | + neighbors.remove(ipaddr); | ||
177 | + } | ||
178 | + this.electDR(); | ||
179 | + } | ||
180 | + | ||
181 | + /** | ||
182 | + * Remove the given neighbor from the neighbor list. | ||
183 | + * | ||
184 | + * @param nbr the nbr to be removed. | ||
185 | + */ | ||
186 | + public void removeNeighbor(PIMNeighbor nbr) { | ||
187 | + | ||
188 | + neighbors.remove(nbr.getPrimaryAddr(), nbr); | ||
189 | + this.electDR(); | ||
190 | + } | ||
191 | + | ||
192 | + /** | ||
193 | + * Elect a new DR on this ConnectPoint. | ||
194 | + * | ||
195 | + * @return the PIM Neighbor that wins | ||
196 | + */ | ||
197 | + public PIMNeighbor electDR() { | ||
198 | + | ||
199 | + for (PIMNeighbor nbr : this.neighbors.values()) { | ||
200 | + if (this.designatedRouter == null) { | ||
201 | + this.designatedRouter = nbr; | ||
202 | + continue; | ||
203 | + } | ||
204 | + | ||
205 | + if (nbr.getPriority() > this.designatedRouter.getPriority()) { | ||
206 | + this.designatedRouter = nbr; | ||
207 | + continue; | ||
208 | + } | ||
209 | + | ||
210 | + // We could sort in ascending order | ||
211 | + if (this.designatedRouter.getPrimaryAddr().compareTo(nbr.getPrimaryAddr()) > 0) { | ||
212 | + this.designatedRouter = nbr; | ||
213 | + continue; | ||
214 | + } | ||
215 | + } | ||
216 | + | ||
217 | + return this.designatedRouter; | ||
218 | + } | ||
219 | + | ||
220 | + /** | ||
221 | + * Elect a new DR given the new neighbor. | ||
222 | + * | ||
223 | + * @param nbr the new neighbor to use in DR election. | ||
224 | + * @return the PIM Neighbor that wins DR election | ||
225 | + */ | ||
226 | + public PIMNeighbor electDR(PIMNeighbor nbr) { | ||
227 | + | ||
228 | + // Make sure I have | ||
229 | + if (this.designatedRouter == null || | ||
230 | + this.designatedRouter.getPriority() < nbr.getPriority() || | ||
231 | + this.designatedRouter.getPrimaryAddr().compareTo(nbr.getPrimaryAddr()) > 0) { | ||
232 | + this.designatedRouter = nbr; | ||
233 | + } | ||
234 | + return this.designatedRouter; | ||
235 | + } | ||
236 | + | ||
237 | + /** | ||
238 | + * Find or create a pim neighbor with a given ip address and connect point. | ||
239 | + * | ||
240 | + * @param ipaddr of the pim neighbor | ||
241 | + * @param mac The mac address of our sending neighbor | ||
242 | + * @return an existing or new PIM neighbor | ||
243 | + */ | ||
244 | + public PIMNeighbor findOrCreate(IpAddress ipaddr, MacAddress mac) { | ||
245 | + PIMNeighbor nbr = this.findNeighbor(ipaddr); | ||
246 | + if (nbr == null) { | ||
247 | + nbr = new PIMNeighbor(ipaddr, mac, this); | ||
248 | + this.addNeighbor(nbr); | ||
249 | + this.electDR(nbr); | ||
250 | + } | ||
251 | + return nbr; | ||
252 | + } | ||
253 | + | ||
254 | + /** | ||
255 | + * Process a hello packet received on this Interface. | ||
256 | + * | ||
257 | + * @param ethPkt the ethernet packet containing the hello message | ||
258 | + * @param cp the ConnectPoint of this interface | ||
259 | + */ | ||
260 | + public void processHello(Ethernet ethPkt, ConnectPoint cp) { | ||
261 | + checkNotNull(ethPkt); | ||
262 | + checkNotNull(cp); | ||
263 | + | ||
264 | + MacAddress srcmac = ethPkt.getSourceMAC(); | ||
265 | + IPv4 ip = (IPv4) ethPkt.getPayload(); | ||
266 | + Ip4Address srcip = Ip4Address.valueOf(ip.getSourceAddress()); | ||
267 | + | ||
268 | + PIM pim = (PIM) ip.getPayload(); | ||
269 | + checkNotNull(pim); | ||
270 | + | ||
271 | + PIMHello hello = (PIMHello) pim.getPayload(); | ||
272 | + checkNotNull(hello); | ||
273 | + | ||
274 | + PIMNeighbor nbr = this.findOrCreate(srcip, srcmac); | ||
275 | + if (nbr == null) { | ||
276 | + log.error("Could not create a neighbor for: {1}", srcip.toString()); | ||
277 | + return; | ||
278 | + } | ||
279 | + | ||
280 | + ConnectPoint icp = theInterface.connectPoint(); | ||
281 | + checkNotNull(icp); | ||
282 | + if (!cp.equals(icp)) { | ||
283 | + log.error("PIM Hello message received from {} on incorrect interface {}", | ||
284 | + nbr.getPrimaryAddr(), this.toString()); | ||
285 | + return; | ||
286 | + } | ||
287 | + nbr.refresh(hello); | ||
288 | + } | ||
289 | + | ||
290 | + /** | ||
291 | + * Send a hello packet from this interface. | ||
292 | + */ | ||
293 | + public void sendHello() { | ||
294 | + PIM pim = new PIM(); | ||
295 | + PIMHello hello = new PIMHello(); | ||
296 | + | ||
297 | + // Create a PIM Hello | ||
298 | + pim = new PIM(); | ||
299 | + pim.setVersion((byte) 2); | ||
300 | + pim.setPIMType((byte) PIM.TYPE_HELLO); | ||
301 | + pim.setChecksum((short) 0); | ||
302 | + | ||
303 | + hello = new PIMHello(); | ||
304 | + hello.createDefaultOptions(); | ||
305 | + pim.setPayload(hello); | ||
306 | + hello.setParent(pim); | ||
307 | + | ||
308 | + log.debug("Sending hello: \n"); | ||
309 | + PIMPacketHandler.getInstance().sendPacket(pim, this); | ||
310 | + } | ||
311 | + | ||
312 | + /** | ||
313 | + * prints the connectPointNeighbors list with each neighbor list. | ||
314 | + * | ||
315 | + * @return string of neighbors. | ||
316 | + */ | ||
317 | + public String printNeighbors() { | ||
318 | + String out = "PIM Neighbors Table: \n"; | ||
319 | + for (PIMNeighbor nbr : this.neighbors.values()) { | ||
320 | + out += "\t" + nbr.toString(); | ||
321 | + } | ||
322 | + return out; | ||
323 | + } | ||
324 | + | ||
325 | + @Override | ||
326 | + public String toString() { | ||
327 | + IpAddress ipaddr = this.getIpAddress(); | ||
328 | + String out = "PIM Neighbors: "; | ||
329 | + if (ipaddr != null) { | ||
330 | + out += "IP: " + ipaddr.toString(); | ||
331 | + } else { | ||
332 | + out += "IP: *Null*"; | ||
333 | + } | ||
334 | + out += "\tPR: " + String.valueOf(this.priority) + "\n"; | ||
335 | + return out; | ||
336 | + } | ||
337 | + | ||
338 | +} | ||
339 | + |
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.jboss.netty.util.Timeout; | ||
19 | +import org.jboss.netty.util.TimerTask; | ||
20 | +import org.onosproject.incubator.net.config.basics.ConfigException; | ||
21 | +import org.onosproject.incubator.net.config.basics.InterfaceConfig; | ||
22 | +import org.onosproject.incubator.net.intf.Interface; | ||
23 | +import org.onosproject.incubator.net.intf.InterfaceService; | ||
24 | +import org.onosproject.net.ConnectPoint; | ||
25 | + | ||
26 | +import java.util.Collection; | ||
27 | +import java.util.HashMap; | ||
28 | +import java.util.Map; | ||
29 | +import java.util.Set; | ||
30 | +import java.util.concurrent.TimeUnit; | ||
31 | + | ||
32 | +import org.onosproject.net.config.NetworkConfigEvent; | ||
33 | +import org.onosproject.net.config.NetworkConfigListener; | ||
34 | +import org.onosproject.net.config.NetworkConfigService; | ||
35 | +import org.slf4j.Logger; | ||
36 | +import org.slf4j.LoggerFactory; | ||
37 | + | ||
38 | +/** | ||
39 | + * PIMInterfaces is a collection of all neighbors we have received | ||
40 | + * PIM hello messages from. The main structure is a HashMap indexed | ||
41 | + * by ConnectPoint with another HashMap indexed on the PIM neighbors | ||
42 | + * IPAddress, it contains all PIM neighbors attached on that ConnectPoint. | ||
43 | + */ | ||
44 | +public final class PIMInterfaces { | ||
45 | + | ||
46 | + private Logger log = LoggerFactory.getLogger("PIMInterfaces"); | ||
47 | + | ||
48 | + private static PIMInterfaces instance = null; | ||
49 | + | ||
50 | + // Used to listen to network configuration changes | ||
51 | + private NetworkConfigService configService; | ||
52 | + | ||
53 | + // Used to access IP Interface definitions for our segment | ||
54 | + private InterfaceService interfaceService; | ||
55 | + | ||
56 | + // Internal class used to listen for network configuration changes | ||
57 | + private InternalConfigListener configListener = new InternalConfigListener(); | ||
58 | + | ||
59 | + // This is the global container for all PIM Interfaces indexed by ConnectPoints. | ||
60 | + private Map<ConnectPoint, PIMInterface> interfaces = new HashMap<>(); | ||
61 | + | ||
62 | + // Default hello message interval | ||
63 | + private int helloMessageInterval = 60; | ||
64 | + | ||
65 | + // Timer used to send hello messages on this interface | ||
66 | + private Timeout helloTimer; | ||
67 | + | ||
68 | + // Required by a utility class | ||
69 | + private PIMInterfaces() {} | ||
70 | + | ||
71 | + /** | ||
72 | + * Get the instance of PIMInterfaces. Create the instance if needed. | ||
73 | + * | ||
74 | + * @return PIMInterface instance | ||
75 | + */ | ||
76 | + public static PIMInterfaces getInstance() { | ||
77 | + if (null == instance) { | ||
78 | + instance = new PIMInterfaces(); | ||
79 | + } | ||
80 | + return instance; | ||
81 | + } | ||
82 | + | ||
83 | + // Initialize the services | ||
84 | + public void initialize(NetworkConfigService cs, InterfaceService is) { | ||
85 | + configService = cs; | ||
86 | + interfaceService = is; | ||
87 | + | ||
88 | + // Initialize interfaces if they already exist | ||
89 | + initInterfaces(); | ||
90 | + | ||
91 | + // Listen for network config changes | ||
92 | + configService.addListener(configListener); | ||
93 | + } | ||
94 | + | ||
95 | + /** | ||
96 | + * Listener for network config events. | ||
97 | + */ | ||
98 | + private class InternalConfigListener implements NetworkConfigListener { | ||
99 | + | ||
100 | + private void updateInterfaces(InterfaceConfig config) { | ||
101 | + Set<Interface> intfs; | ||
102 | + try { | ||
103 | + intfs = config.getInterfaces(); | ||
104 | + } catch (ConfigException e) { | ||
105 | + log.error(e.toString()); | ||
106 | + return; | ||
107 | + } | ||
108 | + for (Interface intf : intfs) { | ||
109 | + addInterface(intf); | ||
110 | + } | ||
111 | + } | ||
112 | + | ||
113 | + /** | ||
114 | + * Remove the PIMInterface represented by the ConnectPoint. If the | ||
115 | + * PIMInterface does not exist this function is a no-op. | ||
116 | + * | ||
117 | + * @param cp The connectPoint representing the PIMInterface to be removed. | ||
118 | + */ | ||
119 | + private void removeInterface(ConnectPoint cp) { | ||
120 | + removeInterface(cp); | ||
121 | + } | ||
122 | + | ||
123 | + @Override | ||
124 | + public void event(NetworkConfigEvent event) { | ||
125 | + switch (event.type()) { | ||
126 | + case CONFIG_ADDED: | ||
127 | + case CONFIG_UPDATED: | ||
128 | + log.debug("Config updated: " + event.toString() + "\n"); | ||
129 | + if (event.configClass() == InterfaceConfig.class) { | ||
130 | + InterfaceConfig config = | ||
131 | + configService.getConfig((ConnectPoint) event.subject(), InterfaceConfig.class); | ||
132 | + updateInterfaces(config); | ||
133 | + } | ||
134 | + break; | ||
135 | + case CONFIG_REMOVED: | ||
136 | + if (event.configClass() == InterfaceConfig.class) { | ||
137 | + removeInterface((ConnectPoint) event.subject()); | ||
138 | + } | ||
139 | + break; | ||
140 | + case CONFIG_REGISTERED: | ||
141 | + case CONFIG_UNREGISTERED: | ||
142 | + default: | ||
143 | + break; | ||
144 | + } | ||
145 | + } | ||
146 | + } | ||
147 | + | ||
148 | + // Configure interfaces if they already exist. | ||
149 | + private void initInterfaces() { | ||
150 | + Set<Interface> intfs = interfaceService.getInterfaces(); | ||
151 | + for (Interface intf : intfs) { | ||
152 | + log.debug("Adding interface: " + intf.toString() + "\n"); | ||
153 | + addInterface(intf); | ||
154 | + } | ||
155 | + } | ||
156 | + | ||
157 | + /** | ||
158 | + * Create a PIM Interface and add to our interfaces list. | ||
159 | + * | ||
160 | + * @param intf the interface to add | ||
161 | + * @return the PIMInterface | ||
162 | + */ | ||
163 | + public PIMInterface addInterface(Interface intf) { | ||
164 | + PIMInterface pif = new PIMInterface(intf); | ||
165 | + interfaces.put(intf.connectPoint(), pif); | ||
166 | + | ||
167 | + // If we have added our first interface start the hello timer. | ||
168 | + if (interfaces.size() == 1) { | ||
169 | + startHelloTimer(); | ||
170 | + } | ||
171 | + | ||
172 | + // Return this interface | ||
173 | + return pif; | ||
174 | + } | ||
175 | + | ||
176 | + /** | ||
177 | + * Remove the PIMInterface from the given ConnectPoint. | ||
178 | + * | ||
179 | + * @param cp the ConnectPoint indexing the PIMInterface to be removed. | ||
180 | + */ | ||
181 | + public void removeInterface(ConnectPoint cp) { | ||
182 | + if (interfaces.containsKey(cp)) { | ||
183 | + interfaces.remove(cp); | ||
184 | + } | ||
185 | + | ||
186 | + if (interfaces.size() == 0) { | ||
187 | + PIMTimer.stop(); | ||
188 | + } | ||
189 | + } | ||
190 | + | ||
191 | + /** | ||
192 | + * Return a collection of PIMInterfaces for use by the PIM Interface codec. | ||
193 | + * | ||
194 | + * @return the collection of PIMInterfaces | ||
195 | + */ | ||
196 | + public Collection<PIMInterface> getInterfaces() { | ||
197 | + return interfaces.values(); | ||
198 | + } | ||
199 | + | ||
200 | + /** | ||
201 | + * Get the PIM Interface indexed by the given ConnectPoint. | ||
202 | + * | ||
203 | + * @param cp the connect point | ||
204 | + * @return the PIMInterface if it exists, NULL if not | ||
205 | + */ | ||
206 | + public PIMInterface getInterface(ConnectPoint cp) { | ||
207 | + return interfaces.get(cp); | ||
208 | + } | ||
209 | + | ||
210 | + /** | ||
211 | + * Return a string of PIMInterfaces for the cli command. | ||
212 | + * | ||
213 | + * @return a string representing PIM interfaces | ||
214 | + */ | ||
215 | + public String printInterfaces() { | ||
216 | + String str = ""; | ||
217 | + for (PIMInterface pi : interfaces.values()) { | ||
218 | + str += pi.toString(); | ||
219 | + } | ||
220 | + return str; | ||
221 | + } | ||
222 | + | ||
223 | + /* ---------------------------------- PIM Hello Timer ----------------------------------- */ | ||
224 | + | ||
225 | + /** | ||
226 | + * Start a new hello timer for this interface. | ||
227 | + */ | ||
228 | + private void startHelloTimer() { | ||
229 | + helloTimer = PIMTimer.getTimer().newTimeout( | ||
230 | + new HelloTimer(), | ||
231 | + helloMessageInterval, | ||
232 | + TimeUnit.SECONDS); | ||
233 | + | ||
234 | + log.debug("Started Hello Timer"); | ||
235 | + } | ||
236 | + | ||
237 | + /** | ||
238 | + * This inner class handles transmitting a PIM hello message on this ConnectPoint. | ||
239 | + */ | ||
240 | + private final class HelloTimer implements TimerTask { | ||
241 | + | ||
242 | + HelloTimer() { | ||
243 | + } | ||
244 | + | ||
245 | + @Override | ||
246 | + public void run(Timeout timeout) throws Exception { | ||
247 | + | ||
248 | + log.debug("Running Hello Timer\n"); | ||
249 | + // Technically we should not send all hello's in synch.. | ||
250 | + for (PIMInterface pi : interfaces.values()) { | ||
251 | + pi.sendHello(); | ||
252 | + } | ||
253 | + | ||
254 | + // restart the hello timer | ||
255 | + if (interfaces.size() > 0) { | ||
256 | + startHelloTimer(); | ||
257 | + } | ||
258 | + } | ||
259 | + } | ||
260 | +} | ||
... | \ No newline at end of file | ... | \ No newline at end of file |
... | @@ -19,16 +19,15 @@ import com.fasterxml.jackson.databind.node.ArrayNode; | ... | @@ -19,16 +19,15 @@ import com.fasterxml.jackson.databind.node.ArrayNode; |
19 | import com.fasterxml.jackson.databind.node.ObjectNode; | 19 | import com.fasterxml.jackson.databind.node.ObjectNode; |
20 | import org.onosproject.codec.CodecContext; | 20 | import org.onosproject.codec.CodecContext; |
21 | import org.onosproject.codec.JsonCodec; | 21 | import org.onosproject.codec.JsonCodec; |
22 | -import org.onosproject.net.ConnectPoint; | ||
23 | 22 | ||
24 | -import java.util.HashMap; | 23 | +import java.util.Collection; |
25 | 24 | ||
26 | import static com.google.common.base.Preconditions.checkNotNull; | 25 | import static com.google.common.base.Preconditions.checkNotNull; |
27 | 26 | ||
28 | /** | 27 | /** |
29 | * PIM neighbors Codec. | 28 | * PIM neighbors Codec. |
30 | */ | 29 | */ |
31 | -public class PIMNeighborsCodec extends JsonCodec<HashMap<ConnectPoint, PIMNeighbors>> { | 30 | +public class PIMInterfacesCodec extends JsonCodec<Collection<PIMInterface>> { |
32 | // JSON field names | 31 | // JSON field names |
33 | //Return Name | 32 | //Return Name |
34 | private static final String CPNBRLIST = "connect_point_list"; | 33 | private static final String CPNBRLIST = "connect_point_list"; |
... | @@ -53,22 +52,22 @@ public class PIMNeighborsCodec extends JsonCodec<HashMap<ConnectPoint, PIMNeighb | ... | @@ -53,22 +52,22 @@ public class PIMNeighborsCodec extends JsonCodec<HashMap<ConnectPoint, PIMNeighb |
53 | * @return Encoded neighbors used by CLI and REST | 52 | * @return Encoded neighbors used by CLI and REST |
54 | */ | 53 | */ |
55 | @Override | 54 | @Override |
56 | - public ObjectNode encode(HashMap<ConnectPoint, PIMNeighbors> cpn, CodecContext context) { | 55 | + public ObjectNode encode(Collection<PIMInterface> cpn, CodecContext context) { |
57 | checkNotNull(cpn, "Pim Neighbors cannot be null"); | 56 | checkNotNull(cpn, "Pim Neighbors cannot be null"); |
58 | 57 | ||
59 | ObjectNode pimNbrJsonCodec = context.mapper().createObjectNode(); | 58 | ObjectNode pimNbrJsonCodec = context.mapper().createObjectNode(); |
60 | ArrayNode cpnList = context.mapper().createArrayNode(); | 59 | ArrayNode cpnList = context.mapper().createArrayNode(); |
61 | 60 | ||
62 | - for (PIMNeighbors pn: cpn.values()) { | 61 | + for (PIMInterface pn: cpn) { |
63 | // get the PimNeighbors Obj, contains Neighbors list | 62 | // get the PimNeighbors Obj, contains Neighbors list |
64 | // create the json object for a single Entry in the Neighbors list | 63 | // create the json object for a single Entry in the Neighbors list |
65 | ObjectNode cp = context.mapper().createObjectNode(); | 64 | ObjectNode cp = context.mapper().createObjectNode(); |
66 | - cp.put(IP, pn.getOurIpAddress().toString()); | 65 | + cp.put(IP, pn.getIpAddress().toString()); |
67 | - cp.put(PRIORITY, String.valueOf(pn.getOurPriority())); | 66 | + cp.put(PRIORITY, String.valueOf(pn.getPriority())); |
68 | 67 | ||
69 | // create the array for the neighbors list | 68 | // create the array for the neighbors list |
70 | ArrayNode nbrsList = context.mapper().createArrayNode(); | 69 | ArrayNode nbrsList = context.mapper().createArrayNode(); |
71 | - for (PIMNeighbor nbr : pn.getOurNeighborsList().values()) { | 70 | + for (PIMNeighbor nbr : pn.getNeighbors()) { |
72 | nbrsList.add(neighbor(nbr, context)); | 71 | nbrsList.add(neighbor(nbr, context)); |
73 | } | 72 | } |
74 | // adds pim neighbor to list | 73 | // adds pim neighbor to list | ... | ... |
... | @@ -60,22 +60,20 @@ public class PIMNeighbor { | ... | @@ -60,22 +60,20 @@ public class PIMNeighbor { |
60 | // Timeout for this neighbor | 60 | // Timeout for this neighbor |
61 | private volatile Timeout timeout; | 61 | private volatile Timeout timeout; |
62 | 62 | ||
63 | - private boolean reelect = false; | ||
64 | - | ||
65 | // A back pointer the neighbors list this neighbor belongs to. | 63 | // A back pointer the neighbors list this neighbor belongs to. |
66 | - private PIMNeighbors neighbors; | 64 | + private PIMInterface pimInterface; |
67 | 65 | ||
68 | /** | 66 | /** |
69 | * Construct this neighbor from the address and connect point. | 67 | * Construct this neighbor from the address and connect point. |
70 | * | 68 | * |
71 | * @param ipaddr IP Address of neighbor | 69 | * @param ipaddr IP Address of neighbor |
72 | * @param macaddr MAC Address of the neighbor | 70 | * @param macaddr MAC Address of the neighbor |
73 | - * @param cp The ConnectPoint of this neighbor | 71 | + * @param pimInterface The PIMInterface of this neighbor |
74 | */ | 72 | */ |
75 | - public PIMNeighbor(IpAddress ipaddr, MacAddress macaddr, ConnectPoint cp) { | 73 | + public PIMNeighbor(IpAddress ipaddr, MacAddress macaddr, PIMInterface pimInterface) { |
76 | this.macAddress = macaddr; | 74 | this.macAddress = macaddr; |
77 | this.primaryAddr = ipaddr; | 75 | this.primaryAddr = ipaddr; |
78 | - this.connectPoint = cp; | 76 | + this.pimInterface = pimInterface; |
79 | this.resetTimeout(); | 77 | this.resetTimeout(); |
80 | } | 78 | } |
81 | 79 | ||
... | @@ -174,30 +172,12 @@ public class PIMNeighbor { | ... | @@ -174,30 +172,12 @@ public class PIMNeighbor { |
174 | * | 172 | * |
175 | * @return the ConnectPoint | 173 | * @return the ConnectPoint |
176 | */ | 174 | */ |
177 | - public ConnectPoint getConnectPoint() { | 175 | + public PIMInterface getPimInterface() { |
178 | - return connectPoint; | 176 | + return pimInterface; |
179 | - } | ||
180 | - | ||
181 | - /** | ||
182 | - * Set the ConnectPoint this router is connected to. | ||
183 | - * | ||
184 | - * @param connectPoint the ConnectPoint this router is connected to. | ||
185 | - */ | ||
186 | - public void setConnectPoint(ConnectPoint connectPoint) { | ||
187 | - this.connectPoint = connectPoint; | ||
188 | } | 177 | } |
189 | 178 | ||
190 | /** | 179 | /** |
191 | - * Set a back pointer to the neighbors list this neighbor is a member of. | 180 | + * We have received a fresh hello from this neighbor, now we need to process it. |
192 | - * | ||
193 | - * @param neighbors the neighbor list this neighbor belongs to | ||
194 | - */ | ||
195 | - public void setNeighbors(PIMNeighbors neighbors) { | ||
196 | - this.neighbors = neighbors; | ||
197 | - } | ||
198 | - | ||
199 | - /** | ||
200 | - * We have received a fresh hello from a neighbor, now we need to process it. | ||
201 | * Depending on the values received in the the hello options may force a | 181 | * Depending on the values received in the the hello options may force a |
202 | * re-election process. | 182 | * re-election process. |
203 | * | 183 | * |
... | @@ -208,17 +188,19 @@ public class PIMNeighbor { | ... | @@ -208,17 +188,19 @@ public class PIMNeighbor { |
208 | public void refresh(PIMHello hello) { | 188 | public void refresh(PIMHello hello) { |
209 | checkNotNull(hello); | 189 | checkNotNull(hello); |
210 | 190 | ||
191 | + boolean reelect = false; | ||
211 | for (PIMHelloOption opt : hello.getOptions().values()) { | 192 | for (PIMHelloOption opt : hello.getOptions().values()) { |
212 | 193 | ||
213 | int len = opt.getOptLength(); | 194 | int len = opt.getOptLength(); |
214 | - byte [] value = new byte[len]; | 195 | + ByteBuffer bb = ByteBuffer.wrap(opt.getValue()); |
215 | - ByteBuffer bb = ByteBuffer.wrap(value); | ||
216 | 196 | ||
217 | switch (opt.getOptType()) { | 197 | switch (opt.getOptType()) { |
218 | case PIMHelloOption.OPT_GENID: | 198 | case PIMHelloOption.OPT_GENID: |
219 | int newid = bb.getInt(); | 199 | int newid = bb.getInt(); |
220 | if (this.genId != newid) { | 200 | if (this.genId != newid) { |
221 | - // TODO: we have a newly rebooted neighbor. Send them our joins. | 201 | + |
202 | + // We have a newly rebooted neighbor, this is where we would | ||
203 | + // send them our joins. | ||
222 | this.genId = newid; | 204 | this.genId = newid; |
223 | } | 205 | } |
224 | break; | 206 | break; |
... | @@ -228,7 +210,7 @@ public class PIMNeighbor { | ... | @@ -228,7 +210,7 @@ public class PIMNeighbor { |
228 | if (this.priority != newpri) { | 210 | if (this.priority != newpri) { |
229 | 211 | ||
230 | // The priorities have changed. We may need to re-elect a new DR? | 212 | // The priorities have changed. We may need to re-elect a new DR? |
231 | - if (this.isDr || this.neighbors.getDesignatedRouter().getPriority() < priority) { | 213 | + if (this.isDr || pimInterface.getDesignatedRouter().getPriority() < priority) { |
232 | reelect = true; | 214 | reelect = true; |
233 | } | 215 | } |
234 | this.priority = newpri; | 216 | this.priority = newpri; |
... | @@ -242,7 +224,6 @@ public class PIMNeighbor { | ... | @@ -242,7 +224,6 @@ public class PIMNeighbor { |
242 | if (holdtime == 0) { | 224 | if (holdtime == 0) { |
243 | // We have a neighbor going down. We can remove all joins | 225 | // We have a neighbor going down. We can remove all joins |
244 | // we have learned from them. | 226 | // we have learned from them. |
245 | - // TODO: What else do we need to do when a neighbor goes down? | ||
246 | 227 | ||
247 | log.debug("PIM Neighbor has timed out: {}", this.primaryAddr.toString()); | 228 | log.debug("PIM Neighbor has timed out: {}", this.primaryAddr.toString()); |
248 | return; | 229 | return; |
... | @@ -261,7 +242,7 @@ public class PIMNeighbor { | ... | @@ -261,7 +242,7 @@ public class PIMNeighbor { |
261 | } | 242 | } |
262 | 243 | ||
263 | if (reelect) { | 244 | if (reelect) { |
264 | - this.neighbors.electDR(this); | 245 | + pimInterface.electDR(this); |
265 | } | 246 | } |
266 | 247 | ||
267 | // Reset the next timeout timer | 248 | // Reset the next timeout timer |
... | @@ -307,9 +288,8 @@ public class PIMNeighbor { | ... | @@ -307,9 +288,8 @@ public class PIMNeighbor { |
307 | @Override | 288 | @Override |
308 | public void run(Timeout timeout) throws Exception { | 289 | public void run(Timeout timeout) throws Exception { |
309 | 290 | ||
310 | - // TODO: log.debug; | 291 | + log.debug("PIM Neighbor {} has timed out: ", nbr.toString()); |
311 | - PIMNeighbors neighbors = nbr.neighbors; | 292 | + nbr.pimInterface.removeNeighbor(nbr); |
312 | - neighbors.removeNeighbor(nbr.getPrimaryAddr()); | ||
313 | } | 293 | } |
314 | } | 294 | } |
315 | 295 | ... | ... |
This diff is collapsed. Click to expand it.
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.Ethernet; | ||
19 | +import org.onlab.packet.IPv4; | ||
20 | +import org.onlab.packet.Ip4Address; | ||
21 | +import org.onlab.packet.IpAddress; | ||
22 | +import org.onlab.packet.IpPrefix; | ||
23 | +import org.onlab.packet.MacAddress; | ||
24 | +import org.onlab.packet.PIM; | ||
25 | +import org.onlab.packet.VlanId; | ||
26 | +import org.onosproject.core.ApplicationId; | ||
27 | +import org.onosproject.incubator.net.intf.Interface; | ||
28 | +import org.onosproject.net.ConnectPoint; | ||
29 | +import org.onosproject.net.flow.DefaultTrafficSelector; | ||
30 | +import org.onosproject.net.flow.DefaultTrafficTreatment; | ||
31 | +import org.onosproject.net.flow.TrafficSelector; | ||
32 | +import org.onosproject.net.flow.TrafficTreatment; | ||
33 | +import org.onosproject.net.packet.DefaultOutboundPacket; | ||
34 | +import org.onosproject.net.packet.InboundPacket; | ||
35 | +import org.onosproject.net.packet.OutboundPacket; | ||
36 | +import org.onosproject.net.packet.PacketContext; | ||
37 | +import org.onosproject.net.packet.PacketPriority; | ||
38 | +import org.onosproject.net.packet.PacketProcessor; | ||
39 | +import org.onosproject.net.packet.PacketService; | ||
40 | +import org.slf4j.Logger; | ||
41 | + | ||
42 | +import java.nio.ByteBuffer; | ||
43 | + | ||
44 | +import static com.google.common.base.Preconditions.checkNotNull; | ||
45 | +import static org.slf4j.LoggerFactory.getLogger; | ||
46 | + | ||
47 | +/** | ||
48 | + * Handing Incoming and outgoing PIM packets. | ||
49 | + */ | ||
50 | +public final class PIMPacketHandler { | ||
51 | + private final Logger log = getLogger(getClass()); | ||
52 | + | ||
53 | + private static PIMPacketHandler instance = null; | ||
54 | + | ||
55 | + private PacketService packetService; | ||
56 | + private PIMPacketProcessor processor = new PIMPacketProcessor(); | ||
57 | + private MacAddress pimDestinationMac = MacAddress.valueOf("01:00:5E:00:00:0d"); | ||
58 | + | ||
59 | + // Utility class | ||
60 | + private PIMPacketHandler() {} | ||
61 | + | ||
62 | + public static PIMPacketHandler getInstance() { | ||
63 | + if (null == instance) { | ||
64 | + instance = new PIMPacketHandler(); | ||
65 | + } | ||
66 | + return instance; | ||
67 | + } | ||
68 | + | ||
69 | + /** | ||
70 | + * Initialize the packet handling service. | ||
71 | + * | ||
72 | + * @param ps the packetService | ||
73 | + * @param appId our application ID | ||
74 | + */ | ||
75 | + public void initialize(PacketService ps, ApplicationId appId) { | ||
76 | + packetService = ps; | ||
77 | + | ||
78 | + // Build a traffic selector for all multicast traffic | ||
79 | + TrafficSelector.Builder selector = DefaultTrafficSelector.builder(); | ||
80 | + selector.matchEthType(Ethernet.TYPE_IPV4); | ||
81 | + selector.matchIPProtocol(IPv4.PROTOCOL_PIM); | ||
82 | + packetService.requestPackets(selector.build(), PacketPriority.REACTIVE, appId); | ||
83 | + | ||
84 | + packetService.addProcessor(processor, PacketProcessor.director(1)); | ||
85 | + } | ||
86 | + | ||
87 | + /** | ||
88 | + * Shutdown the packet handling service. | ||
89 | + */ | ||
90 | + public void stop() { | ||
91 | + packetService.removeProcessor(processor); | ||
92 | + processor = null; | ||
93 | + } | ||
94 | + | ||
95 | + /** | ||
96 | + * Packet processor responsible for handling IGMP packets. | ||
97 | + */ | ||
98 | + public class PIMPacketProcessor implements PacketProcessor { | ||
99 | + private final Logger log = getLogger(getClass()); | ||
100 | + | ||
101 | + @Override | ||
102 | + public void process(PacketContext context) { | ||
103 | + // Stop processing if the packet has been handled, since we | ||
104 | + // can't do any more to it. | ||
105 | + if (context.isHandled()) { | ||
106 | + return; | ||
107 | + } | ||
108 | + | ||
109 | + InboundPacket pkt = context.inPacket(); | ||
110 | + if (pkt == null) { | ||
111 | + return; | ||
112 | + } | ||
113 | + | ||
114 | + Ethernet ethPkt = pkt.parsed(); | ||
115 | + if (ethPkt == null) { | ||
116 | + return; | ||
117 | + } | ||
118 | + | ||
119 | + /* | ||
120 | + * IPv6 MLD packets are handled by ICMP6. We'll only deal | ||
121 | + * with IPv4. | ||
122 | + */ | ||
123 | + if (ethPkt.getEtherType() != Ethernet.TYPE_IPV4) { | ||
124 | + return; | ||
125 | + } | ||
126 | + | ||
127 | + IPv4 ip = (IPv4) ethPkt.getPayload(); | ||
128 | + IpAddress gaddr = IpAddress.valueOf(ip.getDestinationAddress()); | ||
129 | + IpAddress saddr = Ip4Address.valueOf(ip.getSourceAddress()); | ||
130 | + log.debug("Packet (" + saddr.toString() + ", " + gaddr.toString() + | ||
131 | + "\tingress port: " + context.inPacket().receivedFrom().toString()); | ||
132 | + | ||
133 | + if (ip.getProtocol() != IPv4.PROTOCOL_PIM) { | ||
134 | + log.debug("PIM Picked up a non PIM packet: IP protocol: " + ip.getProtocol()); | ||
135 | + return; | ||
136 | + } | ||
137 | + | ||
138 | + // TODO: check incoming to be PIM.PIM_ADDRESS or "Our" address. | ||
139 | + IpPrefix spfx = IpPrefix.valueOf(saddr, 32); | ||
140 | + IpPrefix gpfx = IpPrefix.valueOf(gaddr, 32); | ||
141 | + | ||
142 | + PIM pim = (PIM) ip.getPayload(); | ||
143 | + switch (pim.getPimMsgType()) { | ||
144 | + | ||
145 | + case PIM.TYPE_HELLO: | ||
146 | + processHello(ethPkt, context.inPacket().receivedFrom()); | ||
147 | + break; | ||
148 | + | ||
149 | + case PIM.TYPE_JOIN_PRUNE_REQUEST: | ||
150 | + // Create the function | ||
151 | + break; | ||
152 | + | ||
153 | + case PIM.TYPE_ASSERT: | ||
154 | + case PIM.TYPE_BOOTSTRAP: | ||
155 | + case PIM.TYPE_CANDIDATE_RP_ADV: | ||
156 | + case PIM.TYPE_GRAFT: | ||
157 | + case PIM.TYPE_GRAFT_ACK: | ||
158 | + case PIM.TYPE_REGISTER: | ||
159 | + case PIM.TYPE_REGISTER_STOP: | ||
160 | + log.debug("Unsupported PIM message type: " + pim.getPimMsgType()); | ||
161 | + break; | ||
162 | + | ||
163 | + default: | ||
164 | + log.debug("Unkown PIM message type: " + pim.getPimMsgType()); | ||
165 | + break; | ||
166 | + } | ||
167 | + } | ||
168 | + | ||
169 | + /** | ||
170 | + * Process incoming hello message, we will need the Macaddress and IP address of the sender. | ||
171 | + * | ||
172 | + * @param ethPkt the ethernet header | ||
173 | + * @param receivedFrom the connect point we recieved this message from | ||
174 | + */ | ||
175 | + private void processHello(Ethernet ethPkt, ConnectPoint receivedFrom) { | ||
176 | + checkNotNull(ethPkt); | ||
177 | + checkNotNull(receivedFrom); | ||
178 | + | ||
179 | + // It is a problem if we don't have the | ||
180 | + PIMInterfaces pintfs = PIMInterfaces.getInstance(); | ||
181 | + PIMInterface intf = pintfs.getInterface(receivedFrom); | ||
182 | + if (intf == null) { | ||
183 | + log.error("We received a PIM message on an interface we were not supposed to"); | ||
184 | + return; | ||
185 | + } | ||
186 | + intf.processHello(ethPkt, receivedFrom); | ||
187 | + } | ||
188 | + } | ||
189 | + | ||
190 | + // Create an ethernet header and serialize then send | ||
191 | + public void sendPacket(PIM pim, PIMInterface pimIntf) { | ||
192 | + | ||
193 | + Interface theInterface = pimIntf.getInterface(); | ||
194 | + | ||
195 | + // Create the ethernet packet | ||
196 | + Ethernet eth = new Ethernet(); | ||
197 | + eth.setDestinationMACAddress(pimDestinationMac); | ||
198 | + eth.setSourceMACAddress(theInterface.mac()); | ||
199 | + eth.setEtherType(Ethernet.TYPE_IPV4); | ||
200 | + if (theInterface.vlan() != VlanId.NONE) { | ||
201 | + eth.setVlanID(theInterface.vlan().toShort()); | ||
202 | + } | ||
203 | + | ||
204 | + // Create the IP Packet | ||
205 | + IPv4 ip = new IPv4(); | ||
206 | + ip.setVersion((byte) 4); | ||
207 | + ip.setTtl((byte) 20); | ||
208 | + ip.setProtocol(IPv4.PROTOCOL_PIM); | ||
209 | + ip.setChecksum((short) 0); | ||
210 | + ip.setSourceAddress(checkNotNull(pimIntf.getIpAddress()).getIp4Address().toInt()); | ||
211 | + ip.setDestinationAddress(PIM.PIM_ADDRESS.getIp4Address().toInt()); | ||
212 | + eth.setPayload(ip); | ||
213 | + ip.setParent(eth); | ||
214 | + | ||
215 | + // Now set pim | ||
216 | + ip.setPayload(pim); | ||
217 | + pim.setParent(ip); | ||
218 | + | ||
219 | + ConnectPoint cp = theInterface.connectPoint(); | ||
220 | + checkNotNull(cp); | ||
221 | + | ||
222 | + TrafficTreatment treat = DefaultTrafficTreatment.builder().setOutput(cp.port()).build(); | ||
223 | + ByteBuffer bb = ByteBuffer.wrap(eth.serialize()); | ||
224 | + OutboundPacket packet = new DefaultOutboundPacket(cp.deviceId(), treat, bb); | ||
225 | + checkNotNull(packet); | ||
226 | + | ||
227 | + packetService.emit(packet); | ||
228 | + } | ||
229 | +} |
... | @@ -17,6 +17,8 @@ package org.onosproject.pim.impl; | ... | @@ -17,6 +17,8 @@ package org.onosproject.pim.impl; |
17 | 17 | ||
18 | import org.jboss.netty.util.HashedWheelTimer; | 18 | import org.jboss.netty.util.HashedWheelTimer; |
19 | 19 | ||
20 | +import static com.google.common.base.Preconditions.checkNotNull; | ||
21 | + | ||
20 | /** | 22 | /** |
21 | * PIM Timer used for PIM Neighbors. | 23 | * PIM Timer used for PIM Neighbors. |
22 | */ | 24 | */ |
... | @@ -50,4 +52,21 @@ public final class PIMTimer { | ... | @@ -50,4 +52,21 @@ public final class PIMTimer { |
50 | PIMTimer.timer = hwTimer; | 52 | PIMTimer.timer = hwTimer; |
51 | } | 53 | } |
52 | } | 54 | } |
55 | + | ||
56 | + public static void start() { | ||
57 | + if (PIMTimer.timer == null) { | ||
58 | + getTimer(); | ||
59 | + } | ||
60 | + checkNotNull(timer); | ||
61 | + timer.start(); | ||
62 | + } | ||
63 | + | ||
64 | + public static void stop() { | ||
65 | + if (PIMTimer.timer == null) { | ||
66 | + // No need to stop | ||
67 | + return; | ||
68 | + } | ||
69 | + checkNotNull(timer); | ||
70 | + timer.stop(); | ||
71 | + } | ||
53 | } | 72 | } | ... | ... |
-
Please register or login to post a comment