Rusty Eddy
Committed by Gerrit Code Review

Blew away old version of PIM to restructure. And:

1) Added packetService to register for PIM packets.
2) Added PIMPacketHandler to process PIM packets.
3) Added NetworkConfig Listener
4) Added PIMInterfaceService / PIMInterfaceManager
5) Added Process incoming hello packets to PIMInterfaceManager
6) Code Review inspired changes

Change-Id: I753880c954b9a6a91544903b613305ff9aa78cd0
1 -/*
2 - * Copyright 2014-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.cli;
17 -
18 -import com.fasterxml.jackson.databind.JsonNode;
19 -import org.apache.karaf.shell.commands.Command;
20 -import org.onosproject.cli.AbstractShellCommand;
21 -import org.onosproject.pim.impl.PIMInterface;
22 -import org.onosproject.pim.impl.PIMInterfaces;
23 -import org.onosproject.pim.impl.PIMInterfacesCodec;
24 -
25 -import java.util.Collection;
26 -
27 -@Command(scope = "onos", name = "pim-interfaces", description = "Displays the pim interfaces")
28 -public class PIMShowCommand extends AbstractShellCommand {
29 -
30 - // prints either the json or cli version of the hash map connect point
31 - // neighbors from the PIMInterfaces class.
32 - @Override
33 - protected void execute() {
34 - // grab connect point neighbors hash map to send in to json encoder.
35 - Collection<PIMInterface> pimIntfs = PIMInterfaces.getInstance().getInterfaces();
36 - if (outputJson()) {
37 - print("%s", json(pimIntfs));
38 - } else {
39 - print(PIMInterfaces.getInstance().printInterfaces());
40 - }
41 - }
42 -
43 - private JsonNode json(Collection<PIMInterface> pimIntfs) {
44 - return new PIMInterfacesCodec().encode(pimIntfs, this);
45 - }
46 -
47 -}
...\ No newline at end of file ...\ No newline at end of file
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.apache.felix.scr.annotations.Activate;
19 +import org.apache.felix.scr.annotations.Component;
20 +import org.apache.felix.scr.annotations.Deactivate;
21 +import org.apache.felix.scr.annotations.Reference;
22 +import org.apache.felix.scr.annotations.ReferenceCardinality;
23 +import org.onlab.packet.Ethernet;
24 +import org.onlab.packet.IPv4;
25 +import org.onosproject.core.ApplicationId;
26 +import org.onosproject.core.CoreService;
27 +import org.onosproject.incubator.net.config.basics.ConfigException;
28 +import org.onosproject.incubator.net.config.basics.InterfaceConfig;
29 +import org.onosproject.incubator.net.intf.Interface;
30 +import org.onosproject.incubator.net.intf.InterfaceService;
31 +import org.onosproject.net.ConnectPoint;
32 +import org.onosproject.net.config.NetworkConfigEvent;
33 +import org.onosproject.net.config.NetworkConfigListener;
34 +import org.onosproject.net.config.NetworkConfigService;
35 +import org.onosproject.net.flow.DefaultTrafficSelector;
36 +import org.onosproject.net.flow.TrafficSelector;
37 +import org.onosproject.net.mcast.MulticastRouteService;
38 +import org.onosproject.net.packet.InboundPacket;
39 +import org.onosproject.net.packet.PacketContext;
40 +import org.onosproject.net.packet.PacketProcessor;
41 +import org.onosproject.net.packet.PacketService;
42 +import org.slf4j.Logger;
43 +
44 +import java.util.Set;
45 +
46 +import static org.slf4j.LoggerFactory.getLogger;
47 +
48 +/**
49 + * The main PIM controller class.
50 + */
51 +@Component(immediate = true)
52 +public class PIMApplication {
53 + private final Logger log = getLogger(getClass());
54 +
55 + // Used to get the appId
56 + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
57 + protected CoreService coreService;
58 +
59 + // Our application ID
60 + private static ApplicationId appId;
61 +
62 + // Register to receive PIM packets, used to send packets as well
63 + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
64 + protected PacketService packetService;
65 +
66 + // Use the MulticastRouteService to manage incoming PIM Join/Prune state as well as
67 + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
68 + protected MulticastRouteService ms;
69 +
70 + // Create an instance of the PIM packet handler
71 + protected PIMPacketHandler pimPacketHandler;
72 +
73 + // Get the network configuration updates
74 + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
75 + protected NetworkConfigService configService;
76 +
77 + // Access defined network (IP) interfaces
78 + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
79 + protected InterfaceService interfaceService;
80 +
81 + // Internal class used to listen for network configuration changes
82 + private InternalConfigListener configListener = new InternalConfigListener();
83 +
84 + // Provide interfaces to the pimInterface manager as a result of Netconfig updates.
85 + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
86 + protected PIMInterfaceService pimInterfaceManager;
87 +
88 + /**
89 + * Activate the PIM component.
90 + */
91 + @Activate
92 + public void activate() {
93 +
94 + // Get our application ID
95 + appId = coreService.registerApplication("org.onosproject.pim");
96 +
97 + // Build the traffic selector for PIM packets
98 + TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
99 + selector.matchEthType(Ethernet.TYPE_IPV4);
100 + selector.matchIPProtocol(IPv4.PROTOCOL_PIM);
101 +
102 + // Use the traffic selector to tell the packet service which packets we want.
103 + // PIMPacketService is an inner class defined below
104 + PIMPacketProcessor processor = new PIMPacketProcessor();
105 + packetService.addProcessor(processor, PacketProcessor.director(5));
106 +
107 + // Register for notifications from the Network config & Interface services.
108 + // We'll use these services to represent "PIMInterfaces"
109 +
110 + // Get a copy of the PIM Packet Handler
111 + pimPacketHandler = new PIMPacketHandler();
112 +
113 + // Listen for network configuration changes
114 + configService.addListener(configListener);
115 +
116 + log.info("Started");
117 + }
118 +
119 + /**
120 + * Deactivate the PIM component.
121 + */
122 + @Deactivate
123 + public void deactivate() {
124 + log.info("Stopped");
125 + }
126 +
127 + /**
128 + * The class that will receive PIM packets, sanitize them, determine the PIMInterface
129 + * they arrived on, then forward them on to be processed by the appropriate entity.
130 + */
131 + public class PIMPacketProcessor implements PacketProcessor {
132 + private final Logger log = getLogger(getClass());
133 +
134 + @Override
135 + public void process(PacketContext context) {
136 +
137 + // return if this packet has already been handled
138 + if (context.isHandled()) {
139 + return;
140 + }
141 +
142 + // get the inbound packet
143 + InboundPacket pkt = context.inPacket();
144 + if (pkt == null) {
145 + // problem getting the inbound pkt. Log it debug to avoid spamming log file
146 + log.debug("Could not retrieve packet from context");
147 + return;
148 + }
149 +
150 + // Get the ethernet header
151 + Ethernet eth = pkt.parsed();
152 + if (eth == null) {
153 + // problem getting the ethernet pkt. Log it debug to avoid spamming log file
154 + log.debug("Could not retrieve ethnernet packet from the parsed packet");
155 + return;
156 + }
157 +
158 + // Get the PIM Interface the packet was received on.
159 + PIMInterface pimi = pimInterfaceManager.getPIMInterface(pkt.receivedFrom());
160 + if (pimi == null) {
161 + log.debug("We received PIM packet from a non PIM interface: " + pkt.receivedFrom().toString());
162 + return;
163 + }
164 +
165 + /*
166 + * Pass the packet processing off to the PIMInterface for processing.
167 + *
168 + * TODO: Is it possible that PIM interface processing should move to the
169 + * PIMInterfaceManager directly?
170 + */
171 + PIMPacketHandler ph = new PIMPacketHandler();
172 + ph.processPacket(eth, pimi);
173 + }
174 + }
175 +
176 + /*
177 + * This class receives all events from the network config services, then hands the
178 + * event off to the PIMInterfaceManager for proper handling.
179 + *
180 + * TODO: should this move to PIMInterfaceManager?
181 + */
182 + private class InternalConfigListener implements NetworkConfigListener {
183 +
184 + @Override
185 + public void event(NetworkConfigEvent event) {
186 +
187 + log.debug(event.toString());
188 + switch (event.type()) {
189 + case CONFIG_ADDED:
190 + case CONFIG_UPDATED:
191 +
192 + if (event.configClass() == InterfaceConfig.class) {
193 + InterfaceConfig config = configService.getConfig(
194 + (ConnectPoint) event.subject(),
195 + InterfaceConfig.class);
196 +
197 + log.debug("Got a network configuration event");
198 +
199 + // Walk the interfaces and feed them to the PIMInterfaceManager
200 + Set<Interface> intfs;
201 + try {
202 + intfs = config.getInterfaces();
203 + for (Interface intf : intfs) {
204 + pimInterfaceManager.updateInterface(intf);
205 + }
206 + } catch (ConfigException e) {
207 + log.error(e.toString());
208 + return;
209 + }
210 + }
211 + break;
212 +
213 + case CONFIG_REMOVED:
214 + if (event.configClass() == InterfaceConfig.class) {
215 + ConnectPoint cp = (ConnectPoint) event.subject();
216 + //assertNotNull(cp);
217 + pimInterfaceManager.deleteInterface(cp);
218 + }
219 + break;
220 +
221 + case CONFIG_REGISTERED:
222 + case CONFIG_UNREGISTERED:
223 + default:
224 + log.debug("\tWe are not handling this event type");
225 + break;
226 + }
227 + }
228 + }
229 +}
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 static org.slf4j.LoggerFactory.getLogger;
19 -
20 -import org.apache.felix.scr.annotations.Activate;
21 -import org.apache.felix.scr.annotations.Component;
22 -import org.apache.felix.scr.annotations.Deactivate;
23 -import org.apache.felix.scr.annotations.Reference;
24 -import org.apache.felix.scr.annotations.ReferenceCardinality;
25 -import org.onosproject.core.ApplicationId;
26 -import org.onosproject.core.CoreService;
27 -import org.onosproject.incubator.net.intf.InterfaceService;
28 -import org.onosproject.net.config.NetworkConfigService;
29 -import org.onosproject.net.packet.PacketService;
30 -import org.slf4j.Logger;
31 -
32 -/**
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.
36 - */
37 -@Component(immediate = true)
38 -public class PIMComponent {
39 - private final Logger log = getLogger(getClass());
40 -
41 - // Register to receive PIM packets, used to send packets as well
42 - @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
43 - protected PacketService packetService;
44 -
45 - // Get the appId
46 - @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
47 - protected CoreService coreService;
48 -
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 -
57 - private static ApplicationId appId;
58 -
59 - private PIMInterfaces pimInterfaces;
60 - private PIMPacketHandler pimPacketHandler;
61 -
62 - @Activate
63 - public void activate() {
64 - appId = coreService.registerApplication("org.onosproject.pim");
65 -
66 - // Initialize the Packet Handler class
67 - pimPacketHandler = PIMPacketHandler.getInstance();
68 - pimPacketHandler.initialize(packetService, appId);
69 -
70 - // Initialize the Interface class
71 - pimInterfaces = PIMInterfaces.getInstance();
72 - pimInterfaces.initialize(configService, interfaceService);
73 -
74 - log.info("Started");
75 - }
76 -
77 - @Deactivate
78 - public void deactivate() {
79 - PIMPacketHandler.getInstance().stop();
80 - log.info("Stopped");
81 - }
82 -}
...@@ -17,325 +17,178 @@ package org.onosproject.pim.impl; ...@@ -17,325 +17,178 @@ package org.onosproject.pim.impl;
17 17
18 import org.onlab.packet.Ethernet; 18 import org.onlab.packet.Ethernet;
19 import org.onlab.packet.IPv4; 19 import org.onlab.packet.IPv4;
20 -import org.onlab.packet.Ip4Address;
21 import org.onlab.packet.IpAddress; 20 import org.onlab.packet.IpAddress;
22 import org.onlab.packet.MacAddress; 21 import org.onlab.packet.MacAddress;
23 import org.onlab.packet.PIM; 22 import org.onlab.packet.PIM;
24 import org.onlab.packet.pim.PIMHello; 23 import org.onlab.packet.pim.PIMHello;
25 import org.onlab.packet.pim.PIMHelloOption; 24 import org.onlab.packet.pim.PIMHelloOption;
26 import org.onosproject.incubator.net.intf.Interface; 25 import org.onosproject.incubator.net.intf.Interface;
27 -import org.onosproject.net.ConnectPoint;
28 import org.onosproject.net.host.InterfaceIpAddress; 26 import org.onosproject.net.host.InterfaceIpAddress;
29 import org.slf4j.Logger; 27 import org.slf4j.Logger;
30 -import org.slf4j.LoggerFactory;
31 28
32 -import java.util.Collection; 29 +import java.util.Set;
33 -import java.util.HashMap;
34 -import java.util.Map;
35 30
36 -import static com.google.common.base.Preconditions.checkNotNull; 31 +import static org.slf4j.LoggerFactory.getLogger;
37 32
38 /** 33 /**
39 - * The PIM Interface is a wrapper around a ConnectPoint and used to provide 34 + * PIM Interface represents an ONOS Interface with IP & MAC addresses for
40 - * hello options values when "talking" with PIM other PIM routers. 35 + * a given ConnectPoint.
41 */ 36 */
42 public class PIMInterface { 37 public class PIMInterface {
43 - private static Logger log = LoggerFactory.getLogger("PIMInterfaces");
44 38
45 - // Interface from the interface subsystem 39 + private final Logger log = getLogger(getClass());
46 - private Interface theInterface;
47 40
48 - // The list of PIM neighbors adjacent to this interface 41 + private Interface onosInterface;
49 - private Map<IpAddress, PIMNeighbor> neighbors = new HashMap<>();
50 42
51 - // The designatedRouter for this LAN 43 + // Our hello opt holdtime
52 - private PIMNeighbor designatedRouter; 44 + private short holdtime = PIMHelloOption.DEFAULT_HOLDTIME;
53 45
54 - // The priority we use on this ConnectPoint. 46 + // Our hello opt prune delay
55 - private int priority = PIMHelloOption.DEFAULT_PRIORITY; 47 + private int pruneDelay = PIMHelloOption.DEFAULT_PRUNEDELAY;
56 -
57 - // The holdtime we are sending out.
58 - private int holdtime = PIMHelloOption.DEFAULT_HOLDTIME;
59 48
60 - // Then generation ID we are sending out. 0 means we need to generate a new random ID 49 + // Neighbor priority
61 - private int genid = PIMHelloOption.DEFAULT_GENID; 50 + private int priority = PIMHelloOption.DEFAULT_PRIORITY;
62 51
63 - // Our default prune delay 52 + // Our current genid
64 - private int prunedelay = PIMHelloOption.DEFAULT_PRUNEDELAY; 53 + private int genid = PIMHelloOption.DEFAULT_GENID; // Needs to be assigned.
65 54
66 /** 55 /**
67 - * Create a PIMInterface. 56 + * Create a PIMInterface from an ONOS Interface.
68 * 57 *
69 - * @param intf the network interface configuration 58 + * @param intf the ONOS Interface.
70 */ 59 */
71 public PIMInterface(Interface intf) { 60 public PIMInterface(Interface intf) {
72 - 61 + onosInterface = intf;
73 - log.debug("Adding an interface: " + intf.toString() + "\n");
74 - this.theInterface = intf;
75 -
76 - // Send a hello to let our neighbors know we are alive
77 - sendHello();
78 } 62 }
79 63
80 /** 64 /**
81 - * Get the PIM Interface. 65 + * Return the ONOS Interface.
82 * 66 *
83 - * @return the PIM Interface 67 + * @return ONOS Interface.
84 */ 68 */
85 public Interface getInterface() { 69 public Interface getInterface() {
86 - return theInterface; 70 + return this.onosInterface;
87 } 71 }
88 72
89 /** 73 /**
90 - * Getter for our IP address. 74 + * Set the ONOS Interface, it will override a previous value.
91 * 75 *
92 - * @return our IP address. 76 + * @param intf ONOS Interface.
93 */ 77 */
94 - public IpAddress getIpAddress() { 78 + public PIMInterface setInterface(Interface intf) {
95 - if (theInterface.ipAddresses().isEmpty()) { 79 + this.onosInterface = intf;
96 - return null; 80 + return this;
97 - }
98 -
99 - // We will just assume the first interface on the list
100 - IpAddress ipaddr = null;
101 - for (InterfaceIpAddress ifipaddr : theInterface.ipAddresses()) {
102 - ipaddr = ifipaddr.ipAddress();
103 - break;
104 - }
105 - return ipaddr;
106 } 81 }
107 82
108 /** 83 /**
109 - * Get our priority. 84 + * Get the set of IP Addresses associated with this interface.
110 * 85 *
111 - * @return our priority. 86 + * @return a set of Ip Addresses on this interface
112 */ 87 */
113 - public int getPriority() { 88 + public Set<InterfaceIpAddress> getIpAddresses() {
114 - return this.priority; 89 + return this.onosInterface.ipAddresses();
115 } 90 }
116 91
117 /** 92 /**
118 - * Get the designated router on this connection. 93 + * Return a single "best" IP address.
119 * 94 *
120 - * @return the PIMNeighbor representing the DR 95 + * @return the choosen IP address or null if none
121 */ 96 */
122 - public PIMNeighbor getDesignatedRouter() { 97 + public IpAddress getIpAddress() {
123 - return designatedRouter; 98 + if (onosInterface.ipAddresses().isEmpty()) {
99 + return null;
124 } 100 }
125 101
126 - /** 102 + IpAddress ipaddr = null;
127 - * Are we the DR on this CP? 103 + for (InterfaceIpAddress ifipaddr : onosInterface.ipAddresses()) {
128 - * 104 + ipaddr = ifipaddr.ipAddress();
129 - * @return true if we are, false if not 105 + break;
130 - */
131 - public boolean areWeDr() {
132 - return (designatedRouter != null &&
133 - designatedRouter.getPrimaryAddr().equals(this.getIpAddress()));
134 } 106 }
135 - 107 + return ipaddr;
136 - /**
137 - * Return a collection of PIM Neighbors.
138 - *
139 - * @return the collection of PIM Neighbors
140 - */
141 - public Collection<PIMNeighbor> getNeighbors() {
142 - return this.neighbors.values();
143 } 108 }
144 109
145 /** 110 /**
146 - * Find the neighbor with the given IP address on this CP. 111 + * Get the holdtime.
147 * 112 *
148 - * @param ipaddr the IP address of the neighbor we are interested in 113 + * @return the holdtime
149 - * @return the pim neighbor if it exists
150 */ 114 */
151 - public PIMNeighbor findNeighbor(IpAddress ipaddr) { 115 + public short getHoldtime() {
152 - PIMNeighbor nbr = neighbors.get(ipaddr); 116 + return this.holdtime;
153 - return nbr;
154 } 117 }
155 118
156 /** 119 /**
157 - * Add a new PIM neighbor to this list. 120 + * Get the prune delay.
158 * 121 *
159 - * @param nbr the neighbor to be added. 122 + * @return The prune delay
160 */ 123 */
161 - public void addNeighbor(PIMNeighbor nbr) { 124 + public int getPruneDelay() {
162 - if (neighbors.containsKey(nbr.getPrimaryAddr())) { 125 + return this.pruneDelay;
163 -
164 - log.debug("We are adding a neighbor that already exists: {}", nbr.toString());
165 - neighbors.remove(nbr.getPrimaryAddr());
166 - }
167 - neighbors.put(nbr.getPrimaryAddr(), nbr);
168 } 126 }
169 127
170 /** 128 /**
171 - * Remove the neighbor from our neighbor list. 129 + * Get our hello priority.
172 * 130 *
173 - * @param ipaddr the IP address of the neighbor to remove 131 + * @return our priority
174 */ 132 */
175 - public void removeNeighbor(IpAddress ipaddr) { 133 + public int getPriority() {
176 - 134 + return this.priority;
177 - if (neighbors.containsKey(ipaddr)) {
178 - neighbors.remove(ipaddr);
179 - }
180 - this.electDR();
181 } 135 }
182 136
183 /** 137 /**
184 - * Remove the given neighbor from the neighbor list. 138 + * Get our generation ID.
185 * 139 *
186 - * @param nbr the nbr to be removed. 140 + * @return our generation ID
187 */ 141 */
188 - public void removeNeighbor(PIMNeighbor nbr) { 142 + public int getGenid() {
189 - 143 + return this.genid;
190 - neighbors.remove(nbr.getPrimaryAddr(), nbr);
191 - this.electDR();
192 } 144 }
193 145
194 /** 146 /**
195 - * Elect a new DR on this ConnectPoint. 147 + * Process an incoming PIM Hello message.
196 * 148 *
197 - * @return the PIM Neighbor that wins 149 + * @param ethPkt the Ethernet packet header
198 */ 150 */
199 - public PIMNeighbor electDR() { 151 + public void processHello(Ethernet ethPkt) {
200 152
201 - for (PIMNeighbor nbr : this.neighbors.values()) { 153 + // We'll need to save our neighbors MAC address
202 - if (this.designatedRouter == null) { 154 + MacAddress nbrmac = ethPkt.getSourceMAC();
203 - this.designatedRouter = nbr;
204 - continue;
205 - }
206 155
207 - if (nbr.getPriority() > this.designatedRouter.getPriority()) { 156 + // And we'll need to save neighbors IP Address.
208 - this.designatedRouter = nbr; 157 + IPv4 iphdr = (IPv4) ethPkt.getPayload();
209 - continue; 158 + IpAddress srcip = IpAddress.valueOf(iphdr.getSourceAddress());
210 - }
211 159
212 - // We could sort in ascending order 160 + PIM pimhdr = (PIM) iphdr.getPayload();
213 - if (this.designatedRouter.getPrimaryAddr().compareTo(nbr.getPrimaryAddr()) > 0) { 161 + if (pimhdr.getPimMsgType() != PIM.TYPE_HELLO) {
214 - this.designatedRouter = nbr; 162 + log.error("process Hello has received a non hello packet type: " + pimhdr.getPimMsgType());
215 - continue; 163 + return;
216 - }
217 - }
218 -
219 - return this.designatedRouter;
220 - }
221 -
222 - /**
223 - * Elect a new DR given the new neighbor.
224 - *
225 - * @param nbr the new neighbor to use in DR election.
226 - * @return the PIM Neighbor that wins DR election
227 - */
228 - public PIMNeighbor electDR(PIMNeighbor nbr) {
229 -
230 - // Make sure I have
231 - if (this.designatedRouter == null ||
232 - this.designatedRouter.getPriority() < nbr.getPriority() ||
233 - this.designatedRouter.getPrimaryAddr().compareTo(nbr.getPrimaryAddr()) > 0) {
234 - this.designatedRouter = nbr;
235 - }
236 - return this.designatedRouter;
237 - }
238 -
239 - /**
240 - * Find or create a pim neighbor with a given ip address and connect point.
241 - *
242 - * @param ipaddr of the pim neighbor
243 - * @param mac The mac address of our sending neighbor
244 - * @return an existing or new PIM neighbor
245 - */
246 - public PIMNeighbor findOrCreate(IpAddress ipaddr, MacAddress mac) {
247 - PIMNeighbor nbr = this.findNeighbor(ipaddr);
248 - if (nbr == null) {
249 - nbr = new PIMNeighbor(ipaddr, mac, this);
250 - this.addNeighbor(nbr);
251 - this.electDR(nbr);
252 - }
253 - return nbr;
254 } 164 }
255 165
256 - /** 166 + // TODO: Maybe a good idea to check the checksum. Let's jump into the hello options.
257 - * Process a hello packet received on this Interface. 167 + PIMHello hello = (PIMHello) pimhdr.getPayload();
258 - *
259 - * @param ethPkt the ethernet packet containing the hello message
260 - * @param cp the ConnectPoint of this interface
261 - */
262 - public void processHello(Ethernet ethPkt, ConnectPoint cp) {
263 - checkNotNull(ethPkt);
264 - checkNotNull(cp);
265 168
266 - MacAddress srcmac = ethPkt.getSourceMAC(); 169 + // TODO: this is about where we find or create our PIMNeighbor
267 - IPv4 ip = (IPv4) ethPkt.getPayload();
268 - Ip4Address srcip = Ip4Address.valueOf(ip.getSourceAddress());
269 170
270 - PIM pim = (PIM) ip.getPayload(); 171 + boolean reElectDr = false;
271 - checkNotNull(pim);
272 172
273 - PIMHello hello = (PIMHello) pim.getPayload(); 173 + // Start walking through all the hello options to handle accordingly.
274 - checkNotNull(hello); 174 + for (PIMHelloOption opt : hello.getOptions().values()) {
275 175
276 - PIMNeighbor nbr = this.findOrCreate(srcip, srcmac); 176 + // TODO: This is where we handle the options and modify the neighbor accordingly.
277 - if (nbr == null) { 177 + // We'll need to create the PIMNeighbor class next. Depending on what happens
278 - log.error("Could not create a neighbor for: {1}", srcip.toString()); 178 + // we may need to re-elect a DR
279 - return;
280 } 179 }
281 180
282 - ConnectPoint icp = theInterface.connectPoint(); 181 + if (reElectDr) {
283 - checkNotNull(icp); 182 + // TODO: create an election() method and call it here with a PIMNeighbor
284 - if (!cp.equals(icp)) {
285 - log.error("PIM Hello message received from {} on incorrect interface {}",
286 - nbr.getPrimaryAddr(), this.toString());
287 - return;
288 } 183 }
289 - nbr.refresh(hello);
290 } 184 }
291 185
292 /** 186 /**
293 - * Send a hello packet from this interface. 187 + * Process an incoming PIM JoinPrune message.
294 - */
295 - public void sendHello() {
296 - PIM pim = new PIM();
297 - PIMHello hello = new PIMHello();
298 -
299 - // Create a PIM Hello
300 - pim = new PIM();
301 - pim.setVersion((byte) 2);
302 - pim.setPIMType((byte) PIM.TYPE_HELLO);
303 - pim.setChecksum((short) 0);
304 -
305 - hello = new PIMHello();
306 - hello.createDefaultOptions();
307 - pim.setPayload(hello);
308 - hello.setParent(pim);
309 -
310 - log.debug("Sending hello: \n");
311 - PIMPacketHandler.getInstance().sendPacket(pim, this);
312 - }
313 -
314 - /**
315 - * prints the connectPointNeighbors list with each neighbor list.
316 * 188 *
317 - * @return string of neighbors. 189 + * @param ethPkt the Ethernet packet header.
318 */ 190 */
319 - public String printNeighbors() { 191 + public void processJoinPrune(Ethernet ethPkt) {
320 - String out = "PIM Neighbors Table: \n";
321 - for (PIMNeighbor nbr : this.neighbors.values()) {
322 - out += "\t" + nbr.toString();
323 - }
324 - return out;
325 - }
326 192
327 - @Override
328 - public String toString() {
329 - IpAddress ipaddr = this.getIpAddress();
330 - String out = "PIM Neighbors: ";
331 - if (ipaddr != null) {
332 - out += "IP: " + ipaddr.toString();
333 - } else {
334 - out += "IP: *Null*";
335 - }
336 - out += "\tPR: " + String.valueOf(this.priority) + "\n";
337 - return out;
338 } 193 }
339 -
340 } 194 }
341 -
......
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 com.google.common.collect.Maps;
19 +import org.apache.felix.scr.annotations.Activate;
20 +import org.apache.felix.scr.annotations.Component;
21 +import org.apache.felix.scr.annotations.Deactivate;
22 +import org.apache.felix.scr.annotations.Reference;
23 +import org.apache.felix.scr.annotations.ReferenceCardinality;
24 +import org.apache.felix.scr.annotations.Service;
25 +import org.onosproject.incubator.net.intf.Interface;
26 +import org.onosproject.incubator.net.intf.InterfaceService;
27 +import org.onosproject.net.ConnectPoint;
28 +import org.onosproject.net.provider.ProviderId;
29 +import org.slf4j.Logger;
30 +import java.util.Map;
31 +
32 +import static org.slf4j.LoggerFactory.getLogger;
33 +
34 +/**
35 + * Manages PIMInterfaces.
36 + *
37 + * TODO: Do we need to add a ServiceListener?
38 + */
39 +@Component(immediate = true)
40 +@Service
41 +public class PIMInterfaceManager implements PIMInterfaceService {
42 +
43 + private final Logger log = getLogger(getClass());
44 +
45 + // Create ourselves a provider ID
46 + private static final ProviderId PID = new ProviderId("pim", "org.onosproject.pim");
47 +
48 + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
49 + protected InterfaceService interfaceService;
50 +
51 + // Store PIM Interfaces in a map key'd by ConnectPoint
52 + private final Map<ConnectPoint, PIMInterface> pimInterfaces = Maps.newConcurrentMap();
53 +
54 + @Activate
55 + public void activate() {
56 + // Query the Interface service to see if Interfaces already exist.
57 + log.info("Started");
58 +
59 + // Create PIM Interfaces for each of the existing ONOS Interfaces.
60 + for (Interface intf : interfaceService.getInterfaces()) {
61 + pimInterfaces.put(intf.connectPoint(), new PIMInterface(intf));
62 + }
63 + }
64 +
65 + @Deactivate
66 + public void deactivate() {
67 + log.info("Stopped");
68 + }
69 +
70 + /**
71 + * Update the ONOS Interface with the new Interface. If the PIMInterface does
72 + * not exist we'll create a new one and store it.
73 + *
74 + * @param intf ONOS Interface.
75 + */
76 + @Override
77 + public void updateInterface(Interface intf) {
78 + ConnectPoint cp = intf.connectPoint();
79 +
80 + log.debug("Updating Interface for " + intf.connectPoint().toString());
81 + pimInterfaces.compute(cp, (k, v) -> (v == null) ?
82 + new PIMInterface(intf) :
83 + v.setInterface(intf));
84 + }
85 +
86 + /**
87 + * Delete the PIM Interface to the corresponding ConnectPoint.
88 + *
89 + * @param cp The connect point associated with this interface we want to delete
90 + */
91 + @Override
92 + public void deleteInterface(ConnectPoint cp) {
93 +
94 + PIMInterface pi = pimInterfaces.remove(cp);
95 + if (pi == null) {
96 + log.warn("We've been asked to remove an interface we3 don't have: " + cp.toString());
97 + return;
98 + }
99 + }
100 +
101 + /**
102 + * Return the PIMInterface that corresponds to the given ConnectPoint.
103 + *
104 + * @param cp The ConnectPoint we want to get the PIMInterface for
105 + * @return The PIMInterface if it exists, NULL if it does not exist.
106 + */
107 + @Override
108 + public PIMInterface getPIMInterface(ConnectPoint cp) {
109 + PIMInterface pi = pimInterfaces.getOrDefault(cp, null);
110 + if (pi == null) {
111 + log.warn("We have been asked for an Interface we don't have: " + cp.toString());
112 + }
113 + return pi;
114 + }
115 +}
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.onosproject.incubator.net.intf.Interface;
19 +import org.onosproject.net.ConnectPoint;
20 +
21 +/**
22 + * Define the PIMInterfaceService. PIM will use ONOS Interfaces to
23 + * define PIM Interfaces. The PIM Application signed up as a Netconfig
24 + * listener.
25 + *
26 + * TODO: Do we need a PIMInterfaceListenerService? Who sould listen to Interfaces changes?
27 + */
28 +public interface PIMInterfaceService {
29 +
30 + /**
31 + * Update the corresponding PIMInterface. If the PIMInterface
32 + * does not exist it will be created.
33 + *
34 + * @param intf ONOS Interface.
35 + */
36 + public void updateInterface(Interface intf);
37 +
38 + /**
39 + * Delete the PIMInterface that corresponds to the given ConnectPoint.
40 + *
41 + * @param cp The connect point associated with this interface.
42 + */
43 + public void deleteInterface(ConnectPoint cp);
44 +
45 + /**
46 + * Return the PIMInterface associated with the given ConnectPoint.
47 + *
48 + * @param cp The ConnectPoint we want to get the PIMInterface for.
49 + * @return the PIMInterface if it exists, NULL if it does not exist.
50 + */
51 + public PIMInterface getPIMInterface(ConnectPoint cp);
52 +}
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 - PIMInterfaces.this.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
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 com.fasterxml.jackson.databind.node.ArrayNode;
19 -import com.fasterxml.jackson.databind.node.ObjectNode;
20 -import org.onosproject.codec.CodecContext;
21 -import org.onosproject.codec.JsonCodec;
22 -
23 -import java.util.Collection;
24 -
25 -import static com.google.common.base.Preconditions.checkNotNull;
26 -
27 -/**
28 - * PIM neighbors Codec.
29 - */
30 -public class PIMInterfacesCodec extends JsonCodec<Collection<PIMInterface>> {
31 - // JSON field names
32 - //Return Name
33 - private static final String CPNBRLIST = "connect_point_list";
34 -
35 - // PIM Neightbors Fields
36 - private static final String IP = "ip";
37 - private static final String PRIORITY = "priority";
38 - private static final String NBRLIST = "neighbor_list";
39 -
40 - // PIM neighbor Files
41 - private static final String DR = "designated";
42 - private static final String NBR_IP = "ip";
43 - private static final String PR = "priority";
44 - private static final String HOLDTIME = "hold_time";
45 -
46 - /**
47 - * Encode the PIM Neighbors.
48 - *
49 - * @param cpn ConnectPoint neighbors
50 - * @param context encoding context
51 - *
52 - * @return Encoded neighbors used by CLI and REST
53 - */
54 - @Override
55 - public ObjectNode encode(Collection<PIMInterface> cpn, CodecContext context) {
56 - checkNotNull(cpn, "Pim Neighbors cannot be null");
57 -
58 - ObjectNode pimNbrJsonCodec = context.mapper().createObjectNode();
59 - ArrayNode cpnList = context.mapper().createArrayNode();
60 -
61 - for (PIMInterface pn: cpn) {
62 - // get the PimNeighbors Obj, contains Neighbors list
63 - // create the json object for a single Entry in the Neighbors list
64 - ObjectNode cp = context.mapper().createObjectNode();
65 - cp.put(IP, pn.getIpAddress().toString());
66 - cp.put(PRIORITY, String.valueOf(pn.getPriority()));
67 -
68 - // create the array for the neighbors list
69 - ArrayNode nbrsList = context.mapper().createArrayNode();
70 - for (PIMNeighbor nbr : pn.getNeighbors()) {
71 - nbrsList.add(neighbor(nbr, context));
72 - }
73 - // adds pim neighbor to list
74 - cp.set(NBRLIST, nbrsList);
75 - // adds to arraynode which will represent the connect point neighbors hash map.
76 - cpnList.add(cp);
77 - }
78 - pimNbrJsonCodec.set(CPNBRLIST, cpnList);
79 - return pimNbrJsonCodec;
80 - }
81 -
82 - /**
83 - * Encode a single PIM Neighbor.
84 - *
85 - * @param nbr the neighbor to be encoded
86 - * @param context encoding context
87 - * @return the encoded neighbor
88 - */
89 - private ObjectNode neighbor(PIMNeighbor nbr, CodecContext context) {
90 - return context.mapper().createObjectNode()
91 - .put(DR, Boolean.toString(nbr.isDr()))
92 - .put(NBR_IP, nbr.getPrimaryAddr().toString())
93 - .put(PR, String.valueOf(nbr.getPriority()))
94 - .put(HOLDTIME, String.valueOf(nbr.getHoldtime()));
95 - }
96 -}
1 -/*
2 - * Copyright 2014-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 reliance 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.onlab.packet.IpAddress;
21 -import org.onlab.packet.MacAddress;
22 -import org.onlab.packet.pim.PIMHello;
23 -import org.onlab.packet.pim.PIMHelloOption;
24 -import org.onosproject.net.ConnectPoint;
25 -import org.slf4j.Logger;
26 -
27 -import java.nio.ByteBuffer;
28 -import java.util.concurrent.TimeUnit;
29 -
30 -import static com.google.common.base.Preconditions.checkNotNull;
31 -import static org.slf4j.LoggerFactory.getLogger;
32 -
33 -/**
34 - * PIMNeighbor represents all the PIM routers that have sent us
35 - * hello messages, or that possibly have been statically configured.
36 - */
37 -public class PIMNeighbor {
38 - private final Logger log = getLogger(getClass());
39 -
40 - // The primary address of this PIM neighbor
41 - private IpAddress primaryAddr;
42 -
43 - // The MacAddress of this neighbor
44 - private MacAddress macAddress;
45 -
46 - // The ConnectPoint this PIM neighbor is connected to.
47 - private ConnectPoint connectPoint;
48 -
49 - // Is this neighbor us?
50 - private boolean isThisUs = false;
51 -
52 - // The option values this neighbor has sent us.
53 - private int priority = 0;
54 - private int genId = 0;
55 - private short holdtime = 0;
56 -
57 - // Is this pim neighbor the DR?
58 - private boolean isDr = false;
59 -
60 - // Timeout for this neighbor
61 - private volatile Timeout timeout;
62 -
63 - // A back pointer the neighbors list this neighbor belongs to.
64 - private PIMInterface pimInterface;
65 -
66 - /**
67 - * Construct this neighbor from the address and connect point.
68 - *
69 - * @param ipaddr IP Address of neighbor
70 - * @param macaddr MAC Address of the neighbor
71 - * @param pimInterface The PIMInterface of this neighbor
72 - */
73 - public PIMNeighbor(IpAddress ipaddr, MacAddress macaddr, PIMInterface pimInterface) {
74 - this.macAddress = macaddr;
75 - this.primaryAddr = ipaddr;
76 - this.pimInterface = pimInterface;
77 - this.resetTimeout();
78 - }
79 -
80 - /**
81 - * Get the primary address of this neighbor.
82 - *
83 - * @return the primary IP address.
84 - */
85 - public IpAddress getPrimaryAddr() {
86 - return primaryAddr;
87 - }
88 -
89 - /**
90 - * Set the primary address of this neighbor.
91 - *
92 - * @param primaryAddr the address we'll use when sending hello messages
93 - */
94 - public void setPrimaryAddr(IpAddress primaryAddr) {
95 - this.primaryAddr = primaryAddr;
96 - }
97 -
98 - /**
99 - * Get the priority this neighbor has advertised to us.
100 - *
101 - * @return the priority
102 - */
103 - public int getPriority() {
104 - return priority;
105 - }
106 -
107 - /**
108 - * Set the priority for this neighbor.
109 - *
110 - * @param priority This neighbors priority.
111 - */
112 - public void setPriority(int priority) {
113 - this.priority = priority;
114 - }
115 -
116 - /**
117 - * Get the generation ID.
118 - *
119 - * @return the generation ID.
120 - */
121 - public int getGenId() {
122 - return genId;
123 - }
124 -
125 - /**
126 - * Set the generation ID.
127 - *
128 - * @param genId the generation ID.
129 - */
130 - public void setGenId(int genId) {
131 - this.genId = genId;
132 - }
133 -
134 - /**
135 - * Get the holdtime for this neighbor.
136 - *
137 - * @return the holdtime
138 - */
139 - public short getHoldtime() {
140 - return holdtime;
141 - }
142 -
143 - /**
144 - * Set the holdtime for this neighbor.
145 - *
146 - * @param holdtime the holdtime.
147 - */
148 - public void setholdtime(short holdtime) {
149 - this.holdtime = holdtime;
150 - }
151 -
152 - /**
153 - * Is this neighbor the designated router on this connect point?
154 - *
155 - * @return true if so, false if not.
156 - */
157 - public boolean isDr() {
158 - return isDr;
159 - }
160 -
161 - /**
162 - * Set this router as the designated router on this connect point.
163 - *
164 - * @param isDr True is this neighbor is the DR false otherwise
165 - */
166 - public void setIsDr(boolean isDr) {
167 - this.isDr = isDr;
168 - }
169 -
170 - /**
171 - * The ConnectPoint this neighbor is connected to.
172 - *
173 - * @return the ConnectPoint
174 - */
175 - public PIMInterface getPimInterface() {
176 - return pimInterface;
177 - }
178 -
179 - /**
180 - * We have received a fresh hello from this neighbor, now we need to process it.
181 - * Depending on the values received in the the hello options may force a
182 - * re-election process.
183 - *
184 - * We will also refresh the timeout for this neighbor.
185 - *
186 - * @param hello copy of the hello we'll be able to extract options from.
187 - */
188 - public void refresh(PIMHello hello) {
189 - checkNotNull(hello);
190 -
191 - boolean reelect = false;
192 - for (PIMHelloOption opt : hello.getOptions().values()) {
193 -
194 - int len = opt.getOptLength();
195 - ByteBuffer bb = ByteBuffer.wrap(opt.getValue());
196 -
197 - switch (opt.getOptType()) {
198 - case PIMHelloOption.OPT_GENID:
199 - int newid = bb.getInt();
200 - if (this.genId != newid) {
201 -
202 - // We have a newly rebooted neighbor, this is where we would
203 - // send them our joins.
204 - this.genId = newid;
205 - }
206 - break;
207 -
208 - case PIMHelloOption.OPT_PRIORITY:
209 - int newpri = bb.getInt();
210 - if (this.priority != newpri) {
211 -
212 - // The priorities have changed. We may need to re-elect a new DR?
213 - if (this.isDr || pimInterface.getDesignatedRouter().getPriority() < priority) {
214 - reelect = true;
215 - }
216 - this.priority = newpri;
217 - }
218 - break;
219 -
220 - case PIMHelloOption.OPT_HOLDTIME:
221 - short holdtime = bb.getShort();
222 - if (this.holdtime != holdtime) {
223 - this.holdtime = holdtime;
224 - if (holdtime == 0) {
225 - // We have a neighbor going down. We can remove all joins
226 - // we have learned from them.
227 -
228 - log.debug("PIM Neighbor has timed out: {}", this.primaryAddr.toString());
229 - return;
230 - }
231 - }
232 - break;
233 -
234 - case PIMHelloOption.OPT_PRUNEDELAY:
235 - case PIMHelloOption.OPT_ADDRLIST:
236 - // TODO: implement prune delay and addr list. Fall through for now.
237 -
238 - default:
239 - log.debug("PIM Hello option type: {} not yet supported or unknown.", opt.getOptType());
240 - break;
241 - }
242 - }
243 -
244 - if (reelect) {
245 - pimInterface.electDR(this);
246 - }
247 -
248 - // Reset the next timeout timer
249 - this.resetTimeout();
250 - }
251 -
252 - /* --------------------------------------- Timer functions -------------------------- */
253 -
254 - /**
255 - * Restart the timeout task for this neighbor.
256 - */
257 - private void resetTimeout() {
258 -
259 - if (this.holdtime == 0) {
260 -
261 - // Prepare to die.
262 - log.debug("shutting down timer for nbr {}", this.primaryAddr.toString());
263 - if (this.timeout != null) {
264 - this.timeout.cancel();
265 - this.timeout = null;
266 - }
267 - return;
268 - }
269 -
270 - // Cancel the existing timeout and start a fresh new one.
271 - if (this.timeout != null) {
272 - this.timeout.cancel();
273 - }
274 -
275 - this.timeout = PIMTimer.getTimer().newTimeout(new NeighborTimeoutTask(this), holdtime, TimeUnit.SECONDS);
276 - }
277 -
278 - /**
279 - * The task to run when a neighbor timeout expires.
280 - */
281 - private final class NeighborTimeoutTask implements TimerTask {
282 - PIMNeighbor nbr;
283 -
284 - NeighborTimeoutTask(PIMNeighbor nbr) {
285 - this.nbr = nbr;
286 - }
287 -
288 - @Override
289 - public void run(Timeout timeout) throws Exception {
290 -
291 - log.debug("PIM Neighbor {} has timed out: ", nbr.toString());
292 - nbr.pimInterface.removeNeighbor(nbr);
293 - }
294 - }
295 -
296 - /**
297 - * Stop the timeout timer.
298 - *
299 - * This happens when we remove the neighbor.
300 - */
301 - private final void stopTimeout() {
302 - this.timeout.cancel();
303 - this.timeout = null;
304 - }
305 -
306 - @Override
307 - public String toString() {
308 - String out = "";
309 - if (this.isDr) {
310 - out += "*NBR:";
311 - } else {
312 - out += "NBR:";
313 - }
314 - out += "\tIP: " + this.primaryAddr.toString();
315 - out += "\tPr: " + String.valueOf(this.priority);
316 - out += "\tHoldTime: " + String.valueOf(this.holdtime);
317 - out += "\tGenID: " + String.valueOf(this.genId) + "\n";
318 - return out;
319 - }
320 -}
...\ No newline at end of file ...\ No newline at end of file
...@@ -17,213 +17,74 @@ package org.onosproject.pim.impl; ...@@ -17,213 +17,74 @@ package org.onosproject.pim.impl;
17 17
18 import org.onlab.packet.Ethernet; 18 import org.onlab.packet.Ethernet;
19 import org.onlab.packet.IPv4; 19 import org.onlab.packet.IPv4;
20 -import org.onlab.packet.Ip4Address;
21 import org.onlab.packet.IpAddress; 20 import org.onlab.packet.IpAddress;
22 -import org.onlab.packet.IpPrefix;
23 -import org.onlab.packet.MacAddress;
24 import org.onlab.packet.PIM; 21 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; 22 import org.slf4j.Logger;
41 23
42 -import java.nio.ByteBuffer;
43 -
44 import static com.google.common.base.Preconditions.checkNotNull; 24 import static com.google.common.base.Preconditions.checkNotNull;
45 import static org.slf4j.LoggerFactory.getLogger; 25 import static org.slf4j.LoggerFactory.getLogger;
46 26
47 /** 27 /**
48 - * Handing Incoming and outgoing PIM packets. 28 + * This class will process PIM packets.
49 */ 29 */
50 -public final class PIMPacketHandler { 30 +public 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 31
84 - packetService.addProcessor(processor, PacketProcessor.director(1)); 32 + private final Logger log = getLogger(getClass());
85 - }
86 33
87 /** 34 /**
88 - * Shutdown the packet handling service. 35 + * Constructor for this class.
89 */ 36 */
90 - public void stop() { 37 + public PIMPacketHandler() {
91 - packetService.removeProcessor(processor);
92 - processor = null;
93 } 38 }
94 39
95 /** 40 /**
96 - * Packet processor responsible for handling IGMP packets. 41 + * Sanitize and process the packet.
42 + * TODO: replace ConnectPoint with PIMInterface when PIMInterface has been added.
43 + *
44 + * @param ethPkt the packet starting with the Ethernet header.
45 + * @param pimi the PIM Interface the packet arrived on.
97 */ 46 */
98 - public class PIMPacketProcessor implements PacketProcessor { 47 + public void processPacket(Ethernet ethPkt, PIMInterface pimi) {
99 - private final Logger log = getLogger(getClass()); 48 + checkNotNull(ethPkt);
100 - 49 + checkNotNull(pimi);
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 50
119 - /* 51 + // Sanitize the ethernet header to ensure it is IPv4. IPv6 we'll deal with later
120 - * IPv6 MLD packets are handled by ICMP6. We'll only deal
121 - * with IPv4.
122 - */
123 if (ethPkt.getEtherType() != Ethernet.TYPE_IPV4) { 52 if (ethPkt.getEtherType() != Ethernet.TYPE_IPV4) {
53 + log.debug("Recieved a non IPv4 packet");
124 return; 54 return;
125 } 55 }
126 56
57 + // Get the IP header
127 IPv4 ip = (IPv4) ethPkt.getPayload(); 58 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) { 59 if (ip.getProtocol() != IPv4.PROTOCOL_PIM) {
134 - log.debug("PIM Picked up a non PIM packet: IP protocol: " + ip.getProtocol()); 60 + log.debug("Received a non PIM IP packet");
135 return; 61 return;
136 } 62 }
137 63
138 - // TODO: check incoming to be PIM.PIM_ADDRESS or "Our" address. 64 + // Get the address of our the neighbor that sent this packet to us.
139 - IpPrefix spfx = IpPrefix.valueOf(saddr, 32); 65 + IpAddress nbraddr = IpAddress.valueOf(ip.getDestinationAddress());
140 - IpPrefix gpfx = IpPrefix.valueOf(gaddr, 32); 66 + log.debug("Packet " + nbraddr.toString() + " received on port " + pimi.toString());
141 67
68 + // Get the PIM header
142 PIM pim = (PIM) ip.getPayload(); 69 PIM pim = (PIM) ip.getPayload();
70 + checkNotNull(pim);
71 +
72 + // Process the pim packet
143 switch (pim.getPimMsgType()) { 73 switch (pim.getPimMsgType()) {
144 74
145 case PIM.TYPE_HELLO: 75 case PIM.TYPE_HELLO:
146 - processHello(ethPkt, context.inPacket().receivedFrom()); 76 + pimi.processHello(ethPkt);
77 + log.debug("Received a PIM hello packet");
147 break; 78 break;
148 79
149 case PIM.TYPE_JOIN_PRUNE_REQUEST: 80 case PIM.TYPE_JOIN_PRUNE_REQUEST:
150 - // Create the function 81 + pimi.processJoinPrune(ethPkt);
151 - break; 82 + log.debug("Received a PIM Join/Prune message");
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; 83 break;
162 84
163 default: 85 default:
164 - log.debug("Unkown PIM message type: " + pim.getPimMsgType()); 86 + log.debug("Recieved unsupported PIM type: " + pim.getPimMsgType());
165 break; 87 break;
166 } 88 }
167 } 89 }
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 } 90 }
......
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.HashedWheelTimer;
19 -
20 -import static com.google.common.base.Preconditions.checkNotNull;
21 -
22 -/**
23 - * PIM Timer used for PIM Neighbors.
24 - */
25 -public final class PIMTimer {
26 -
27 - private static volatile HashedWheelTimer timer;
28 -
29 - // Ban public construction
30 - private PIMTimer() {
31 - }
32 -
33 - /**
34 - * Returns the singleton hashed-wheel timer.
35 - *
36 - * @return hashed-wheel timer
37 - */
38 - public static HashedWheelTimer getTimer() {
39 - if (PIMTimer.timer == null) {
40 - initTimer();
41 - }
42 - return PIMTimer.timer;
43 - }
44 -
45 - // Start the PIM timer.
46 - private static synchronized void initTimer() {
47 - if (PIMTimer.timer == null) {
48 -
49 - // Create and start a new hashed wheel timer, if it does not exist.
50 - HashedWheelTimer hwTimer = new HashedWheelTimer();
51 - hwTimer.start();
52 - PIMTimer.timer = hwTimer;
53 - }
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 - }
72 -}
...@@ -53,7 +53,6 @@ import java.util.stream.Collectors; ...@@ -53,7 +53,6 @@ import java.util.stream.Collectors;
53 53
54 import static org.slf4j.LoggerFactory.getLogger; 54 import static org.slf4j.LoggerFactory.getLogger;
55 55
56 -
57 /** 56 /**
58 * Provides implementation of the meter service APIs. 57 * Provides implementation of the meter service APIs.
59 */ 58 */
......