Jonathan Hart

Added configuration for PIM interfaces.

Now the PIM application requires PIM Interface configuration for each interface
that will have PIM enabled (no longer uses all ONOS interfaces). The
interface-specific PIM parameters can be tuned.

Change-Id: Ibc284fdbe1b3aa4da48097b3e92470bce4f349a7
...@@ -82,37 +82,4 @@ ...@@ -82,37 +82,4 @@
82 </dependency> 82 </dependency>
83 </dependencies> 83 </dependencies>
84 84
85 - <build>
86 - <plugins>
87 - <plugin>
88 - <groupId>org.apache.felix</groupId>
89 - <artifactId>maven-bundle-plugin</artifactId>
90 - <extensions>true</extensions>
91 - <configuration>
92 - <instructions>
93 - <Bundle-SymbolicName>
94 - ${project.groupId}.${project.artifactId}
95 - </Bundle-SymbolicName>
96 - <Import-Package>
97 - org.slf4j,
98 - org.osgi.framework,
99 - com.google.common.*,
100 - org.apache.karaf.shell.commands,
101 - org.apache.karaf.shell.console,
102 - org.onlab.packet.*,
103 - org.onosproject.*,
104 - </Import-Package>
105 - </instructions>
106 - </configuration>
107 - </plugin>
108 - <plugin>
109 - <groupId>org.apache.maven.plugins</groupId>
110 - <artifactId>maven-compiler-plugin</artifactId>
111 - <configuration>
112 - <source>1.8</source>
113 - <target>1.8</target>
114 - </configuration>
115 - </plugin>
116 - </plugins>
117 - </build>
118 </project> 85 </project>
......
1 +/*
2 + * Copyright 2016 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 +
17 +package org.onosproject.pim.cli;
18 +
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.PIMInterfaceService;
23 +
24 +import java.util.Set;
25 +
26 +/**
27 + * Lists the interfaces where PIM is enabled.
28 + */
29 +@Command(scope = "onos", name = "pim-interfaces",
30 + description = "Lists the interfaces where PIM is enabled")
31 +public class PimInterfacesListCommand extends AbstractShellCommand {
32 +
33 + private static final String FORMAT = "interfaceName=%s, holdTime=%s, priority=%s, genId=%s";
34 +
35 + @Override
36 + protected void execute() {
37 + PIMInterfaceService interfaceService = get(PIMInterfaceService.class);
38 +
39 + Set<PIMInterface> interfaces = interfaceService.getPimInterfaces();
40 +
41 + interfaces.forEach(
42 + pimIntf -> print(FORMAT, pimIntf.getInterface().name(),
43 + pimIntf.getHoldtime(), pimIntf.getPriority(),
44 + pimIntf.getGenerationId()));
45 + }
46 +
47 +}
...@@ -24,14 +24,6 @@ import org.onlab.packet.Ethernet; ...@@ -24,14 +24,6 @@ import org.onlab.packet.Ethernet;
24 import org.onlab.packet.IPv4; 24 import org.onlab.packet.IPv4;
25 import org.onosproject.core.ApplicationId; 25 import org.onosproject.core.ApplicationId;
26 import org.onosproject.core.CoreService; 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; 27 import org.onosproject.net.flow.DefaultTrafficSelector;
36 import org.onosproject.net.flow.TrafficSelector; 28 import org.onosproject.net.flow.TrafficSelector;
37 import org.onosproject.net.mcast.MulticastRouteService; 29 import org.onosproject.net.mcast.MulticastRouteService;
...@@ -43,7 +35,6 @@ import org.onosproject.net.packet.PacketService; ...@@ -43,7 +35,6 @@ import org.onosproject.net.packet.PacketService;
43 import org.slf4j.Logger; 35 import org.slf4j.Logger;
44 36
45 import java.util.Optional; 37 import java.util.Optional;
46 -import java.util.Set;
47 38
48 import static org.slf4j.LoggerFactory.getLogger; 39 import static org.slf4j.LoggerFactory.getLogger;
49 40
...@@ -72,17 +63,6 @@ public class PIMApplication { ...@@ -72,17 +63,6 @@ public class PIMApplication {
72 // Create an instance of the PIM packet handler 63 // Create an instance of the PIM packet handler
73 protected PIMPacketHandler pimPacketHandler; 64 protected PIMPacketHandler pimPacketHandler;
74 65
75 - // Get the network configuration updates
76 - @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
77 - protected NetworkConfigService configService;
78 -
79 - // Access defined network (IP) interfaces
80 - @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
81 - protected InterfaceService interfaceService;
82 -
83 - // Internal class used to listen for network configuration changes
84 - private InternalConfigListener configListener = new InternalConfigListener();
85 -
86 // Provide interfaces to the pimInterface manager as a result of Netconfig updates. 66 // Provide interfaces to the pimInterface manager as a result of Netconfig updates.
87 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) 67 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
88 protected PIMInterfaceService pimInterfaceManager; 68 protected PIMInterfaceService pimInterfaceManager;
...@@ -94,7 +74,6 @@ public class PIMApplication { ...@@ -94,7 +74,6 @@ public class PIMApplication {
94 */ 74 */
95 @Activate 75 @Activate
96 public void activate() { 76 public void activate() {
97 -
98 // Get our application ID 77 // Get our application ID
99 appId = coreService.registerApplication("org.onosproject.pim"); 78 appId = coreService.registerApplication("org.onosproject.pim");
100 79
...@@ -109,15 +88,9 @@ public class PIMApplication { ...@@ -109,15 +88,9 @@ public class PIMApplication {
109 packetService.requestPackets(selector.build(), PacketPriority.CONTROL, 88 packetService.requestPackets(selector.build(), PacketPriority.CONTROL,
110 appId, Optional.empty()); 89 appId, Optional.empty());
111 90
112 - // Register for notifications from the Network config & Interface services.
113 - // We'll use these services to represent "PIMInterfaces"
114 -
115 // Get a copy of the PIM Packet Handler 91 // Get a copy of the PIM Packet Handler
116 pimPacketHandler = new PIMPacketHandler(); 92 pimPacketHandler = new PIMPacketHandler();
117 93
118 - // Listen for network configuration changes
119 - configService.addListener(configListener);
120 -
121 log.info("Started"); 94 log.info("Started");
122 } 95 }
123 96
...@@ -180,57 +153,4 @@ public class PIMApplication { ...@@ -180,57 +153,4 @@ public class PIMApplication {
180 } 153 }
181 } 154 }
182 155
183 - /*
184 - * This class receives all events from the network config services, then hands the
185 - * event off to the PIMInterfaceManager for proper handling.
186 - *
187 - * TODO: should this move to PIMInterfaceManager?
188 - */
189 - private class InternalConfigListener implements NetworkConfigListener {
190 -
191 - @Override
192 - public void event(NetworkConfigEvent event) {
193 -
194 - log.debug(event.toString());
195 - switch (event.type()) {
196 - case CONFIG_ADDED:
197 - case CONFIG_UPDATED:
198 -
199 - if (event.configClass() == InterfaceConfig.class) {
200 - InterfaceConfig config = configService.getConfig(
201 - (ConnectPoint) event.subject(),
202 - InterfaceConfig.class);
203 -
204 - log.debug("Got a network configuration event");
205 -
206 - // Walk the interfaces and feed them to the PIMInterfaceManager
207 - Set<Interface> intfs;
208 - try {
209 - intfs = config.getInterfaces();
210 - for (Interface intf : intfs) {
211 - pimInterfaceManager.updateInterface(intf);
212 - }
213 - } catch (ConfigException e) {
214 - log.error(e.toString());
215 - return;
216 - }
217 - }
218 - break;
219 -
220 - case CONFIG_REMOVED:
221 - if (event.configClass() == InterfaceConfig.class) {
222 - ConnectPoint cp = (ConnectPoint) event.subject();
223 - //assertNotNull(cp);
224 - pimInterfaceManager.deleteInterface(cp);
225 - }
226 - break;
227 -
228 - case CONFIG_REGISTERED:
229 - case CONFIG_UNREGISTERED:
230 - default:
231 - log.debug("\tWe are not handling this event type");
232 - break;
233 - }
234 - }
235 - }
236 } 156 }
......
...@@ -34,8 +34,10 @@ import org.slf4j.Logger; ...@@ -34,8 +34,10 @@ import org.slf4j.Logger;
34 import java.nio.ByteBuffer; 34 import java.nio.ByteBuffer;
35 import java.util.HashMap; 35 import java.util.HashMap;
36 import java.util.Map; 36 import java.util.Map;
37 +import java.util.Random;
37 import java.util.Set; 38 import java.util.Set;
38 39
40 +import static com.google.common.base.Preconditions.checkArgument;
39 import static com.google.common.base.Preconditions.checkNotNull; 41 import static com.google.common.base.Preconditions.checkNotNull;
40 import static org.slf4j.LoggerFactory.getLogger; 42 import static org.slf4j.LoggerFactory.getLogger;
41 43
...@@ -43,7 +45,7 @@ import static org.slf4j.LoggerFactory.getLogger; ...@@ -43,7 +45,7 @@ import static org.slf4j.LoggerFactory.getLogger;
43 * PIM Interface represents an ONOS Interface with IP and MAC addresses for 45 * PIM Interface represents an ONOS Interface with IP and MAC addresses for
44 * a given ConnectPoint. 46 * a given ConnectPoint.
45 */ 47 */
46 -public class PIMInterface { 48 +public final class PIMInterface {
47 49
48 private final Logger log = getLogger(getClass()); 50 private final Logger log = getLogger(getClass());
49 51
...@@ -62,10 +64,10 @@ public class PIMInterface { ...@@ -62,10 +64,10 @@ public class PIMInterface {
62 private int priority = PIMHelloOption.DEFAULT_PRIORITY; 64 private int priority = PIMHelloOption.DEFAULT_PRIORITY;
63 65
64 // Our current genid 66 // Our current genid
65 - private int genid = PIMHelloOption.DEFAULT_GENID; // Needs to be assigned. 67 + private final int generationId;
66 68
67 // The IP address of the DR 69 // The IP address of the DR
68 - IpAddress drIpaddress; 70 + private IpAddress drIpaddress;
69 71
70 // A map of all our PIM neighbors keyed on our neighbors IP address 72 // A map of all our PIM neighbors keyed on our neighbors IP address
71 private Map<IpAddress, PIMNeighbor> pimNeighbors = new HashMap<>(); 73 private Map<IpAddress, PIMNeighbor> pimNeighbors = new HashMap<>();
...@@ -74,14 +76,28 @@ public class PIMInterface { ...@@ -74,14 +76,28 @@ public class PIMInterface {
74 * Create a PIMInterface from an ONOS Interface. 76 * Create a PIMInterface from an ONOS Interface.
75 * 77 *
76 * @param intf the ONOS Interface. 78 * @param intf the ONOS Interface.
79 + * @param holdTime hold time
80 + * @param priority priority
81 + * @param propagationDelay propagation delay
82 + * @param overrideInterval override interval
83 + * @param packetService reference to the packet service
77 */ 84 */
78 - public PIMInterface(Interface intf, PacketService packetService) { 85 + private PIMInterface(Interface intf,
86 + short holdTime,
87 + int priority,
88 + short propagationDelay,
89 + short overrideInterval,
90 + PacketService packetService) {
91 +
79 onosInterface = intf; 92 onosInterface = intf;
80 outputTreatment = createOutputTreatment(); 93 outputTreatment = createOutputTreatment();
94 + this.holdtime = holdTime;
81 this.packetService = packetService; 95 this.packetService = packetService;
82 IpAddress ourIp = getIpAddress(); 96 IpAddress ourIp = getIpAddress();
83 MacAddress mac = intf.mac(); 97 MacAddress mac = intf.mac();
84 98
99 + generationId = new Random().nextInt();
100 +
85 // Create a PIM Neighbor to represent ourselves for DR election. 101 // Create a PIM Neighbor to represent ourselves for DR election.
86 PIMNeighbor us = new PIMNeighbor(ourIp, mac); 102 PIMNeighbor us = new PIMNeighbor(ourIp, mac);
87 103
...@@ -178,8 +194,8 @@ public class PIMInterface { ...@@ -178,8 +194,8 @@ public class PIMInterface {
178 * 194 *
179 * @return our generation ID 195 * @return our generation ID
180 */ 196 */
181 - public int getGenid() { 197 + public int getGenerationId() {
182 - return genid; 198 + return generationId;
183 } 199 }
184 200
185 /** 201 /**
...@@ -188,7 +204,6 @@ public class PIMInterface { ...@@ -188,7 +204,6 @@ public class PIMInterface {
188 * result of a newly created interface. 204 * result of a newly created interface.
189 */ 205 */
190 public void sendHello() { 206 public void sendHello() {
191 -
192 // Create the base PIM Packet and mark it a hello packet 207 // Create the base PIM Packet and mark it a hello packet
193 PIMPacket pimPacket = new PIMPacket(PIM.TYPE_HELLO); 208 PIMPacket pimPacket = new PIMPacket(PIM.TYPE_HELLO);
194 209
...@@ -199,6 +214,9 @@ public class PIMInterface { ...@@ -199,6 +214,9 @@ public class PIMInterface {
199 // Create the hello message with options 214 // Create the hello message with options
200 PIMHello hello = new PIMHello(); 215 PIMHello hello = new PIMHello();
201 hello.createDefaultOptions(); 216 hello.createDefaultOptions();
217 + hello.addOption(PIMHelloOption.createHoldTime(holdtime));
218 + hello.addOption(PIMHelloOption.createPriority(priority));
219 + hello.addOption(PIMHelloOption.createGenID(generationId));
202 220
203 // Now set the hello option payload 221 // Now set the hello option payload
204 pimPacket.setPIMPayload(hello); 222 pimPacket.setPIMPayload(hello);
...@@ -266,7 +284,7 @@ public class PIMInterface { ...@@ -266,7 +284,7 @@ public class PIMInterface {
266 nbr.refreshTimestamp(); 284 nbr.refreshTimestamp();
267 285
268 /* 286 /*
269 - * the election method will frist determine if an election 287 + * the election method will first determine if an election
270 * needs to be run, if so it will run the election. The 288 * needs to be run, if so it will run the election. The
271 * IP address of the DR will be returned. If the IP address 289 * IP address of the DR will be returned. If the IP address
272 * of the DR is different from what we already have we know a 290 * of the DR is different from what we already have we know a
...@@ -280,17 +298,17 @@ public class PIMInterface { ...@@ -280,17 +298,17 @@ public class PIMInterface {
280 } 298 }
281 299
282 // Run an election if we need to. Return the elected IP address. 300 // Run an election if we need to. Return the elected IP address.
283 - private IpAddress election(PIMNeighbor nbr, IpAddress drip, int drpri) { 301 + private IpAddress election(PIMNeighbor nbr, IpAddress drIp, int drPriority) {
284 302
285 - IpAddress nbrip = nbr.getIpaddr(); 303 + IpAddress nbrIp = nbr.getIpaddr();
286 - if (nbr.getPriority() > drpri) { 304 + if (nbr.getPriority() > drPriority) {
287 - return nbrip; 305 + return nbrIp;
288 } 306 }
289 307
290 - if (nbrip.compareTo(drip) > 0) { 308 + if (nbrIp.compareTo(drIp) > 0) {
291 - return nbrip; 309 + return nbrIp;
292 } 310 }
293 - return drip; 311 + return drIp;
294 } 312 }
295 313
296 /** 314 /**
...@@ -301,4 +319,105 @@ public class PIMInterface { ...@@ -301,4 +319,105 @@ public class PIMInterface {
301 public void processJoinPrune(Ethernet ethPkt) { 319 public void processJoinPrune(Ethernet ethPkt) {
302 // TODO: add Join/Prune processing code. 320 // TODO: add Join/Prune processing code.
303 } 321 }
322 +
323 + /**
324 + * Returns a builder for a PIM interface.
325 + *
326 + * @return PIM interface builder
327 + */
328 + public static Builder builder() {
329 + return new Builder();
330 + }
331 +
332 + /**
333 + * Builder for a PIM interface.
334 + */
335 + public static class Builder {
336 + private Interface intf;
337 + private PacketService packetService;
338 + private short holdtime = PIMHelloOption.DEFAULT_HOLDTIME;
339 + private int priority = PIMHelloOption.DEFAULT_PRIORITY;
340 + private short propagationDelay = PIMHelloOption.DEFAULT_PRUNEDELAY;
341 + private short overrideInterval = PIMHelloOption.DEFAULT_OVERRIDEINTERVAL;
342 +
343 + /**
344 + * Uses the specified ONOS interface.
345 + *
346 + * @param intf ONOS interface
347 + * @return this PIM interface builder
348 + */
349 + public Builder withInterface(Interface intf) {
350 + this.intf = checkNotNull(intf);
351 + return this;
352 + }
353 +
354 + /**
355 + * Sets the reference to the packet service.
356 + *
357 + * @param packetService packet service
358 + * @return this PIM interface builder
359 + */
360 + public Builder withPacketService(PacketService packetService) {
361 + this.packetService = checkNotNull(packetService);
362 + return this;
363 + }
364 +
365 + /**
366 + * Uses the specified hold time.
367 + *
368 + * @param holdTime hold time in seconds
369 + * @return this PIM interface builder
370 + */
371 + public Builder withHoldTime(short holdTime) {
372 + this.holdtime = holdTime;
373 + return this;
374 + }
375 +
376 + /**
377 + * Uses the specified DR priority.
378 + *
379 + * @param priority DR priority
380 + * @return this PIM interface builder
381 + */
382 + public Builder withPriority(int priority) {
383 + this.priority = priority;
384 + return this;
385 + }
386 +
387 + /**
388 + * Uses the specified propagation delay.
389 + *
390 + * @param propagationDelay propagation delay in ms
391 + * @return this PIM interface builder
392 + */
393 + public Builder withPropagationDelay(short propagationDelay) {
394 + this.propagationDelay = propagationDelay;
395 + return this;
396 + }
397 +
398 + /**
399 + * Uses the specified override interval.
400 + *
401 + * @param overrideInterval override interval in ms
402 + * @return this PIM interface builder
403 + */
404 + public Builder withOverrideInterval(short overrideInterval) {
405 + this.overrideInterval = overrideInterval;
406 + return this;
407 + }
408 +
409 + /**
410 + * Builds the PIM interface.
411 + *
412 + * @return PIM interface
413 + */
414 + public PIMInterface build() {
415 + checkArgument(intf != null, "Must provide an interface");
416 + checkArgument(packetService != null, "Must provide a packet service");
417 +
418 + return new PIMInterface(intf, holdtime, priority, propagationDelay,
419 + overrideInterval, packetService);
420 + }
421 +
422 + }
304 } 423 }
......
...@@ -15,6 +15,7 @@ ...@@ -15,6 +15,7 @@
15 */ 15 */
16 package org.onosproject.pim.impl; 16 package org.onosproject.pim.impl;
17 17
18 +import com.google.common.collect.ImmutableSet;
18 import com.google.common.collect.Maps; 19 import com.google.common.collect.Maps;
19 import org.apache.felix.scr.annotations.Activate; 20 import org.apache.felix.scr.annotations.Activate;
20 import org.apache.felix.scr.annotations.Component; 21 import org.apache.felix.scr.annotations.Component;
...@@ -23,12 +24,20 @@ import org.apache.felix.scr.annotations.Reference; ...@@ -23,12 +24,20 @@ import org.apache.felix.scr.annotations.Reference;
23 import org.apache.felix.scr.annotations.ReferenceCardinality; 24 import org.apache.felix.scr.annotations.ReferenceCardinality;
24 import org.apache.felix.scr.annotations.Service; 25 import org.apache.felix.scr.annotations.Service;
25 import org.onosproject.incubator.net.intf.Interface; 26 import org.onosproject.incubator.net.intf.Interface;
27 +import org.onosproject.incubator.net.intf.InterfaceEvent;
28 +import org.onosproject.incubator.net.intf.InterfaceListener;
26 import org.onosproject.incubator.net.intf.InterfaceService; 29 import org.onosproject.incubator.net.intf.InterfaceService;
27 import org.onosproject.net.ConnectPoint; 30 import org.onosproject.net.ConnectPoint;
31 +import org.onosproject.net.config.ConfigFactory;
32 +import org.onosproject.net.config.NetworkConfigEvent;
33 +import org.onosproject.net.config.NetworkConfigListener;
34 +import org.onosproject.net.config.NetworkConfigRegistry;
35 +import org.onosproject.net.config.basics.SubjectFactories;
28 import org.onosproject.net.packet.PacketService; 36 import org.onosproject.net.packet.PacketService;
29 -import org.onosproject.net.provider.ProviderId;
30 import org.slf4j.Logger; 37 import org.slf4j.Logger;
38 +
31 import java.util.Map; 39 import java.util.Map;
40 +import java.util.Set;
32 import java.util.concurrent.Executors; 41 import java.util.concurrent.Executors;
33 import java.util.concurrent.ScheduledExecutorService; 42 import java.util.concurrent.ScheduledExecutorService;
34 import java.util.concurrent.TimeUnit; 43 import java.util.concurrent.TimeUnit;
...@@ -46,8 +55,8 @@ public class PIMInterfaceManager implements PIMInterfaceService { ...@@ -46,8 +55,8 @@ public class PIMInterfaceManager implements PIMInterfaceService {
46 55
47 private final Logger log = getLogger(getClass()); 56 private final Logger log = getLogger(getClass());
48 57
49 - // Create ourselves a provider ID 58 + private static final Class<PimInterfaceConfig> PIM_INTERFACE_CONFIG_CLASS = PimInterfaceConfig.class;
50 - private static final ProviderId PID = new ProviderId("pim", "org.onosproject.pim"); 59 + private static final String PIM_INTERFACE_CONFIG_KEY = "pimInterface";
51 60
52 // Create a Scheduled Executor service to send PIM hellos 61 // Create a Scheduled Executor service to send PIM hellos
53 private final ScheduledExecutorService helloScheduler = 62 private final ScheduledExecutorService helloScheduler =
...@@ -55,43 +64,76 @@ public class PIMInterfaceManager implements PIMInterfaceService { ...@@ -55,43 +64,76 @@ public class PIMInterfaceManager implements PIMInterfaceService {
55 64
56 // Wait for a bout 3 seconds before sending the initial hello messages. 65 // Wait for a bout 3 seconds before sending the initial hello messages.
57 // TODO: make this tunnable. 66 // TODO: make this tunnable.
58 - private final long initialHelloDelay = (long) 3; 67 + private final long initialHelloDelay = 3;
59 68
60 // Send PIM hello packets: 30 seconds. 69 // Send PIM hello packets: 30 seconds.
61 - private final long pimHelloPeriod = (long) 30; 70 + private final long pimHelloPeriod = 30;
62 71
63 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) 72 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
64 - protected InterfaceService interfaceService; 73 + protected PacketService packetService;
65 74
66 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) 75 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
67 - protected PacketService packetService; 76 + protected NetworkConfigRegistry networkConfig;
77 +
78 + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
79 + protected InterfaceService interfaceService;
68 80
69 // Store PIM Interfaces in a map key'd by ConnectPoint 81 // Store PIM Interfaces in a map key'd by ConnectPoint
70 private final Map<ConnectPoint, PIMInterface> pimInterfaces = Maps.newConcurrentMap(); 82 private final Map<ConnectPoint, PIMInterface> pimInterfaces = Maps.newConcurrentMap();
71 83
84 + private final InternalNetworkConfigListener configListener =
85 + new InternalNetworkConfigListener();
86 + private final InternalInterfaceListener interfaceListener =
87 + new InternalInterfaceListener();
88 +
89 + private final ConfigFactory<ConnectPoint, PimInterfaceConfig> pimConfigFactory
90 + = new ConfigFactory<ConnectPoint, PimInterfaceConfig>(
91 + SubjectFactories.CONNECT_POINT_SUBJECT_FACTORY, PIM_INTERFACE_CONFIG_CLASS,
92 + PIM_INTERFACE_CONFIG_KEY) {
93 +
94 + @Override
95 + public PimInterfaceConfig createConfig() {
96 + return new PimInterfaceConfig();
97 + }
98 + };
99 +
72 @Activate 100 @Activate
73 public void activate() { 101 public void activate() {
74 - // Query the Interface service to see if Interfaces already exist. 102 + networkConfig.registerConfigFactory(pimConfigFactory);
75 - log.info("Started");
76 103
77 - // Create PIM Interfaces for each of the existing ONOS Interfaces. 104 + // Create PIM Interfaces for each of the existing configured interfaces.
78 - for (Interface intf : interfaceService.getInterfaces()) { 105 + Set<ConnectPoint> subjects = networkConfig.getSubjects(
79 - pimInterfaces.put(intf.connectPoint(), new PIMInterface(intf, packetService)); 106 + ConnectPoint.class, PIM_INTERFACE_CONFIG_CLASS);
107 + for (ConnectPoint cp : subjects) {
108 + PimInterfaceConfig config = networkConfig.getConfig(cp, PIM_INTERFACE_CONFIG_CLASS);
109 + updateInterface(config);
80 } 110 }
81 111
112 + networkConfig.addListener(configListener);
113 + interfaceService.addListener(interfaceListener);
114 +
82 // Schedule the periodic hello sender. 115 // Schedule the periodic hello sender.
83 helloScheduler.scheduleAtFixedRate(new Runnable() { 116 helloScheduler.scheduleAtFixedRate(new Runnable() {
84 @Override 117 @Override
85 public void run() { 118 public void run() {
119 + try {
86 for (PIMInterface pif : pimInterfaces.values()) { 120 for (PIMInterface pif : pimInterfaces.values()) {
87 pif.sendHello(); 121 pif.sendHello();
88 } 122 }
123 + } catch (Exception e) {
124 + log.warn("exception", e);
125 + }
89 } 126 }
90 }, initialHelloDelay, pimHelloPeriod, TimeUnit.SECONDS); 127 }, initialHelloDelay, pimHelloPeriod, TimeUnit.SECONDS);
128 +
129 + log.info("Started");
91 } 130 }
92 131
93 @Deactivate 132 @Deactivate
94 public void deactivate() { 133 public void deactivate() {
134 + interfaceService.removeListener(interfaceListener);
135 + networkConfig.removeListener(configListener);
136 + networkConfig.unregisterConfigFactory(pimConfigFactory);
95 137
96 // Shutdown the periodic hello task. 138 // Shutdown the periodic hello task.
97 helloScheduler.shutdown(); 139 helloScheduler.shutdown();
...@@ -100,48 +142,128 @@ public class PIMInterfaceManager implements PIMInterfaceService { ...@@ -100,48 +142,128 @@ public class PIMInterfaceManager implements PIMInterfaceService {
100 } 142 }
101 143
102 /** 144 /**
103 - * Update the ONOS Interface with the new Interface. If the PIMInterface does 145 + * Return the PIMInterface that corresponds to the given ConnectPoint.
104 - * not exist we'll create a new one and store it.
105 * 146 *
106 - * @param intf ONOS Interface. 147 + * @param cp The ConnectPoint we want to get the PIMInterface for
148 + * @return The PIMInterface if it exists, NULL if it does not exist.
107 */ 149 */
108 @Override 150 @Override
109 - public void updateInterface(Interface intf) { 151 + public PIMInterface getPIMInterface(ConnectPoint cp) {
110 - ConnectPoint cp = intf.connectPoint(); 152 + PIMInterface pi = pimInterfaces.getOrDefault(cp, null);
153 + if (pi == null) {
154 + log.warn("We have been asked for an Interface we don't have: " + cp.toString());
155 + }
156 + return pi;
157 + }
158 +
159 + @Override
160 + public Set<PIMInterface> getPimInterfaces() {
161 + return ImmutableSet.copyOf(pimInterfaces.values());
162 + }
163 +
164 + private void updateInterface(PimInterfaceConfig config) {
165 + ConnectPoint cp = config.subject();
166 +
167 + if (!config.isEnabled()) {
168 + removeInterface(cp);
169 + return;
170 + }
171 +
172 + String intfName = config.getInterfaceName();
173 + Interface intf = interfaceService.getInterfaceByName(cp, intfName);
174 +
175 + if (intf == null) {
176 + log.debug("Interface configuration missing: {}", config.getInterfaceName());
177 + return;
178 + }
179 +
111 180
112 log.debug("Updating Interface for " + intf.connectPoint().toString()); 181 log.debug("Updating Interface for " + intf.connectPoint().toString());
113 - pimInterfaces.compute(cp, (k, v) -> (v == null) ? 182 + pimInterfaces.computeIfAbsent(cp, k -> buildPimInterface(config, intf));
114 - new PIMInterface(intf, packetService) : 183 + }
115 - v.setInterface(intf)); 184 +
185 + private void removeInterface(ConnectPoint cp) {
186 + pimInterfaces.remove(cp);
187 + }
188 +
189 + private PIMInterface buildPimInterface(PimInterfaceConfig config, Interface intf) {
190 + PIMInterface.Builder builder = PIMInterface.builder()
191 + .withPacketService(packetService)
192 + .withInterface(intf);
193 +
194 + if (config.getHoldTime().isPresent()) {
195 + builder.withHoldTime(config.getHoldTime().get());
196 + }
197 + if (config.getPriority().isPresent()) {
198 + builder.withPriority(config.getPriority().get());
199 + }
200 + if (config.getPropagationDelay().isPresent()) {
201 + builder.withPropagationDelay(config.getPropagationDelay().get());
202 + }
203 + if (config.getOverrideInterval().isPresent()) {
204 + builder.withOverrideInterval(config.getOverrideInterval().get());
205 + }
206 +
207 + return builder.build();
116 } 208 }
117 209
118 /** 210 /**
119 - * Delete the PIM Interface to the corresponding ConnectPoint. 211 + * Listener for network config events.
120 - *
121 - * @param cp The connect point associated with this interface we want to delete
122 */ 212 */
123 - @Override 213 + private class InternalNetworkConfigListener implements NetworkConfigListener {
124 - public void deleteInterface(ConnectPoint cp) {
125 214
126 - PIMInterface pi = pimInterfaces.remove(cp); 215 + @Override
127 - if (pi == null) { 216 + public void event(NetworkConfigEvent event) {
128 - log.warn("We've been asked to remove an interface we3 don't have: " + cp.toString()); 217 + if (event.configClass() != PIM_INTERFACE_CONFIG_CLASS) {
129 return; 218 return;
130 } 219 }
220 +
221 + switch (event.type()) {
222 + case CONFIG_REGISTERED:
223 + case CONFIG_UNREGISTERED:
224 + break;
225 + case CONFIG_ADDED:
226 + case CONFIG_UPDATED:
227 + ConnectPoint cp = (ConnectPoint) event.subject();
228 + PimInterfaceConfig config = networkConfig.getConfig(
229 + cp, PIM_INTERFACE_CONFIG_CLASS);
230 +
231 + updateInterface(config);
232 + break;
233 + case CONFIG_REMOVED:
234 + removeInterface((ConnectPoint) event.subject());
235 + break;
236 + default:
237 + break;
238 + }
239 + }
131 } 240 }
132 241
133 /** 242 /**
134 - * Return the PIMInterface that corresponds to the given ConnectPoint. 243 + * Listener for interface events.
135 - *
136 - * @param cp The ConnectPoint we want to get the PIMInterface for
137 - * @return The PIMInterface if it exists, NULL if it does not exist.
138 */ 244 */
245 + private class InternalInterfaceListener implements InterfaceListener {
246 +
139 @Override 247 @Override
140 - public PIMInterface getPIMInterface(ConnectPoint cp) { 248 + public void event(InterfaceEvent event) {
141 - PIMInterface pi = pimInterfaces.getOrDefault(cp, null); 249 + switch (event.type()) {
142 - if (pi == null) { 250 + case INTERFACE_ADDED:
143 - log.warn("We have been asked for an Interface we don't have: " + cp.toString()); 251 + PimInterfaceConfig config = networkConfig.getConfig(
252 + event.subject().connectPoint(), PIM_INTERFACE_CONFIG_CLASS);
253 +
254 + if (config != null) {
255 + updateInterface(config);
256 + }
257 + break;
258 + case INTERFACE_UPDATED:
259 + break;
260 + case INTERFACE_REMOVED:
261 + removeInterface(event.subject().connectPoint());
262 + break;
263 + default:
264 + break;
265 +
266 + }
144 } 267 }
145 - return pi;
146 } 268 }
147 } 269 }
......
...@@ -15,9 +15,10 @@ ...@@ -15,9 +15,10 @@
15 */ 15 */
16 package org.onosproject.pim.impl; 16 package org.onosproject.pim.impl;
17 17
18 -import org.onosproject.incubator.net.intf.Interface;
19 import org.onosproject.net.ConnectPoint; 18 import org.onosproject.net.ConnectPoint;
20 19
20 +import java.util.Set;
21 +
21 /** 22 /**
22 * Define the PIMInterfaceService. PIM will use ONOS Interfaces to 23 * Define the PIMInterfaceService. PIM will use ONOS Interfaces to
23 * define PIM Interfaces. The PIM Application signed up as a Netconfig 24 * define PIM Interfaces. The PIM Application signed up as a Netconfig
...@@ -28,25 +29,17 @@ import org.onosproject.net.ConnectPoint; ...@@ -28,25 +29,17 @@ import org.onosproject.net.ConnectPoint;
28 public interface PIMInterfaceService { 29 public interface PIMInterfaceService {
29 30
30 /** 31 /**
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. 32 * Return the PIMInterface associated with the given ConnectPoint.
47 * 33 *
48 * @param cp The ConnectPoint we want to get the PIMInterface for. 34 * @param cp The ConnectPoint we want to get the PIMInterface for.
49 * @return the PIMInterface if it exists, NULL if it does not exist. 35 * @return the PIMInterface if it exists, NULL if it does not exist.
50 */ 36 */
51 public PIMInterface getPIMInterface(ConnectPoint cp); 37 public PIMInterface getPIMInterface(ConnectPoint cp);
38 +
39 + /**
40 + * Retrieves the set of all interfaces running PIM.
41 + *
42 + * @return set of PIM interfaces
43 + */
44 + Set<PIMInterface> getPimInterfaces();
52 } 45 }
......
1 +/*
2 + * Copyright 2016 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 +
17 +package org.onosproject.pim.impl;
18 +
19 +import org.onosproject.net.ConnectPoint;
20 +import org.onosproject.net.config.Config;
21 +
22 +import java.util.Optional;
23 +
24 +/**
25 + * Configuration for a PIM interface.
26 + */
27 +public class PimInterfaceConfig extends Config<ConnectPoint> {
28 +
29 + private static final String INTERFACE_NAME = "interfaceName";
30 + private static final String ENABLED = "enabled";
31 + private static final String HOLD_TIME = "holdTime";
32 + private static final String PRIORITY = "priority";
33 + private static final String PROPAGATION_DELAY = "propagationDelay";
34 + private static final String OVERRIDE_INTERVAL = "overrideInterval";
35 +
36 + /**
37 + * Gets the name of the interface. This links the PIM configuration with
38 + * an existing ONOS interface.
39 + *
40 + * @return interface name
41 + */
42 + public String getInterfaceName() {
43 + return node.path(INTERFACE_NAME).asText();
44 + }
45 +
46 + /**
47 + * Returns whether PIM is enabled on the interface or not.
48 + *
49 + * @return true if PIM is enabled, otherwise false
50 + */
51 + public boolean isEnabled() {
52 + return node.path(ENABLED).asBoolean(false);
53 + }
54 +
55 + /**
56 + * Gets the HELLO hold time of the interface.
57 + *
58 + * @return hold time
59 + */
60 + public Optional<Short> getHoldTime() {
61 + if (node.path(HOLD_TIME).isMissingNode()) {
62 + return Optional.empty();
63 + }
64 + return Optional.of(Short.parseShort(node.path(HOLD_TIME).asText()));
65 + }
66 +
67 + /**
68 + * Gets the priority of the interface.
69 + *
70 + * @return priority
71 + */
72 + public Optional<Integer> getPriority() {
73 + if (node.path(PRIORITY).isMissingNode()) {
74 + return Optional.empty();
75 + }
76 + return Optional.of(node.path(PRIORITY).asInt());
77 + }
78 +
79 + /**
80 + * Gets the propagation delay of the interface.
81 + *
82 + * @return propagation delay
83 + */
84 + public Optional<Short> getPropagationDelay() {
85 + if (node.path(PROPAGATION_DELAY).isMissingNode()) {
86 + return Optional.empty();
87 + }
88 + return Optional.of(Short.parseShort(node.path(PROPAGATION_DELAY).asText()));
89 + }
90 +
91 + /**
92 + * Gets the override interval of the interface.
93 + *
94 + * @return override interval
95 + */
96 + public Optional<Short> getOverrideInterval() {
97 + if (node.path(OVERRIDE_INTERVAL).isMissingNode()) {
98 + return Optional.empty();
99 + }
100 + return Optional.of(Short.parseShort(node.path(OVERRIDE_INTERVAL).asText()));
101 + }
102 +}
...@@ -17,7 +17,7 @@ ...@@ -17,7 +17,7 @@
17 17
18 <command-bundle xmlns="http://karaf.apache.org/xmlns/shell/v1.1.0"> 18 <command-bundle xmlns="http://karaf.apache.org/xmlns/shell/v1.1.0">
19 <command> 19 <command>
20 - <action class="org.onosproject.pim.cli.PIMShowCommand"/> 20 + <action class="org.onosproject.pim.cli.PimInterfacesListCommand"/>
21 </command> 21 </command>
22 </command-bundle> 22 </command-bundle>
23 23
......
...@@ -23,29 +23,43 @@ import java.text.MessageFormat; ...@@ -23,29 +23,43 @@ import java.text.MessageFormat;
23 import static org.onlab.packet.PacketUtils.checkBufferLength; 23 import static org.onlab.packet.PacketUtils.checkBufferLength;
24 import static org.onlab.packet.PacketUtils.checkInput; 24 import static org.onlab.packet.PacketUtils.checkInput;
25 25
26 +/**
27 + * PIM HELLO option.
28 + */
26 public class PIMHelloOption { 29 public class PIMHelloOption {
27 30
28 - /** 31 + /*
29 * PIM Option types. 32 * PIM Option types.
30 */ 33 */
31 public static final short OPT_HOLDTIME = 1; 34 public static final short OPT_HOLDTIME = 1;
35 + public static final short HOLDTIME_LENGTH = 2;
36 + public static final short DEFAULT_HOLDTIME = 105;
37 +
32 public static final short OPT_PRUNEDELAY = 2; 38 public static final short OPT_PRUNEDELAY = 2;
33 - public static final short OPT_PRIORITY = 19; 39 + public static final short PRUNEDELAY_LENGTH = 4;
34 - public static final short OPT_GENID = 20; 40 + public static final short DEFAULT_PRUNEDELAY = 500; // 500 ms
35 - public static final short OPT_ADDRLIST = 24; 41 + public static final short DEFAULT_OVERRIDEINTERVAL = 2500; // 2500 ms
36 42
37 - public static final short DEFAULT_HOLDTIME = 105; 43 + public static final short OPT_PRIORITY = 19;
38 - public static final int DEFAULT_PRUNEDELAY = 2000; // 2,000 ms 44 + public static final short PRIORITY_LENGTH = 4;
39 public static final int DEFAULT_PRIORITY = 1; 45 public static final int DEFAULT_PRIORITY = 1;
46 +
47 + public static final short OPT_GENID = 20;
48 + public static final short GENID_LENGTH = 4;
40 public static final int DEFAULT_GENID = 0; 49 public static final int DEFAULT_GENID = 0;
41 50
51 + public static final short OPT_ADDRLIST = 24;
52 +
42 public static final int MINIMUM_OPTION_LEN_BYTES = 4; 53 public static final int MINIMUM_OPTION_LEN_BYTES = 4;
43 54
44 // Values for this particular hello option. 55 // Values for this particular hello option.
45 - private short optType; 56 + private short optType = 0;
46 - private short optLength; 57 + private short optLength = 0;
47 private byte[] optValue; 58 private byte[] optValue;
48 59
60 + /**
61 + * Constructs a new hello option with no fields set.
62 + */
49 public PIMHelloOption() { 63 public PIMHelloOption() {
50 } 64 }
51 65
...@@ -59,25 +73,25 @@ public class PIMHelloOption { ...@@ -59,25 +73,25 @@ public class PIMHelloOption {
59 this.optType = type; 73 this.optType = type;
60 switch (type) { 74 switch (type) {
61 case OPT_HOLDTIME: 75 case OPT_HOLDTIME:
62 - this.optLength = 2; 76 + this.optLength = HOLDTIME_LENGTH;
63 this.optValue = new byte[optLength]; 77 this.optValue = new byte[optLength];
64 ByteBuffer.wrap(this.optValue).putShort(PIMHelloOption.DEFAULT_HOLDTIME); 78 ByteBuffer.wrap(this.optValue).putShort(PIMHelloOption.DEFAULT_HOLDTIME);
65 break; 79 break;
66 80
67 case OPT_PRUNEDELAY: 81 case OPT_PRUNEDELAY:
68 - this.optLength = 4; 82 + this.optLength = PRUNEDELAY_LENGTH;
69 this.optValue = new byte[this.optLength]; 83 this.optValue = new byte[this.optLength];
70 ByteBuffer.wrap(this.optValue).putInt(PIMHelloOption.DEFAULT_PRUNEDELAY); 84 ByteBuffer.wrap(this.optValue).putInt(PIMHelloOption.DEFAULT_PRUNEDELAY);
71 break; 85 break;
72 86
73 case OPT_PRIORITY: 87 case OPT_PRIORITY:
74 - this.optLength = 4; 88 + this.optLength = PRIORITY_LENGTH;
75 this.optValue = new byte[this.optLength]; 89 this.optValue = new byte[this.optLength];
76 ByteBuffer.wrap(this.optValue).putInt(PIMHelloOption.DEFAULT_PRIORITY); 90 ByteBuffer.wrap(this.optValue).putInt(PIMHelloOption.DEFAULT_PRIORITY);
77 break; 91 break;
78 92
79 case OPT_GENID: 93 case OPT_GENID:
80 - this.optLength = 4; 94 + this.optLength = GENID_LENGTH;
81 this.optValue = new byte[this.optLength]; 95 this.optValue = new byte[this.optLength];
82 ByteBuffer.wrap(this.optValue).putInt(PIMHelloOption.DEFAULT_GENID); 96 ByteBuffer.wrap(this.optValue).putInt(PIMHelloOption.DEFAULT_GENID);
83 break; 97 break;
...@@ -109,17 +123,85 @@ public class PIMHelloOption { ...@@ -109,17 +123,85 @@ public class PIMHelloOption {
109 return this.optLength; 123 return this.optLength;
110 } 124 }
111 125
112 - public void setValue(ByteBuffer bb) throws DeserializationException { 126 + public void setValue(ByteBuffer bb) {
113 this.optValue = new byte[this.optLength]; 127 this.optValue = new byte[this.optLength];
114 bb.get(this.optValue, 0, this.optLength); 128 bb.get(this.optValue, 0, this.optLength);
115 } 129 }
116 130
131 + public void setValue(byte[] value) {
132 + this.optValue = value;
133 + }
134 +
117 public byte[] getValue() { 135 public byte[] getValue() {
118 return this.optValue; 136 return this.optValue;
119 } 137 }
120 138
139 + /**
140 + * Creates a new PIM Hello option with the specified values.
141 + *
142 + * @param type hello option type
143 + * @param length option length
144 + * @param value option value
145 + * @return new PIM Hello option
146 + */
147 + public static PIMHelloOption create(short type, short length, ByteBuffer value) {
148 + PIMHelloOption option = new PIMHelloOption();
149 + option.setOptType(type);
150 + option.setOptLength(length);
151 + value.rewind();
152 + option.setValue(value);
153 + return option;
154 + }
155 +
156 + /**
157 + * Creates a new priority option.
158 + *
159 + * @param priority priority
160 + * @return priority option
161 + */
162 + public static PIMHelloOption createPriority(int priority) {
163 + return create(OPT_PRIORITY, PRIORITY_LENGTH,
164 + ByteBuffer.allocate(PRIORITY_LENGTH).putInt(priority));
165 + }
166 +
167 + /**
168 + * Creates a new hold time option.
169 + *
170 + * @param holdTime hold time
171 + * @return hold time option
172 + */
173 + public static PIMHelloOption createHoldTime(short holdTime) {
174 + return create(OPT_HOLDTIME, HOLDTIME_LENGTH,
175 + ByteBuffer.allocate(HOLDTIME_LENGTH).putShort(holdTime));
176 + }
177 +
178 + /**
179 + * Creates a new generation ID option with a particular generation ID.
180 + *
181 + * @param genId generation ID value
182 + * @return generation ID option
183 + */
184 + public static PIMHelloOption createGenID(int genId) {
185 + return create(OPT_GENID, GENID_LENGTH,
186 + ByteBuffer.allocate(GENID_LENGTH).putInt(genId));
187 + }
188 +
189 + /**
190 + * Creates a new LAN Prune Delay option.
191 + *
192 + * @param propagationDelay prune delay
193 + * @param overrideInterval override interval
194 + * @return prune delay option
195 + */
196 + public static PIMHelloOption createPruneDelay(short propagationDelay, short overrideInterval) {
197 + return create(OPT_PRUNEDELAY, PRUNEDELAY_LENGTH,
198 + ByteBuffer.allocate(PRUNEDELAY_LENGTH)
199 + .putShort(propagationDelay)
200 + .putShort(overrideInterval));
201 + }
202 +
121 public static PIMHelloOption deserialize(ByteBuffer bb) throws DeserializationException { 203 public static PIMHelloOption deserialize(ByteBuffer bb) throws DeserializationException {
122 - checkInput(bb.array(), bb.position(), bb.limit() - bb.position(), 4); 204 + checkInput(bb.array(), bb.position(), bb.limit() - bb.position(), MINIMUM_OPTION_LEN_BYTES);
123 205
124 PIMHelloOption opt = new PIMHelloOption(); 206 PIMHelloOption opt = new PIMHelloOption();
125 opt.setOptType(bb.getShort()); 207 opt.setOptType(bb.getShort());
...@@ -132,7 +214,7 @@ public class PIMHelloOption { ...@@ -132,7 +214,7 @@ public class PIMHelloOption {
132 } 214 }
133 215
134 public byte[] serialize() { 216 public byte[] serialize() {
135 - int len = 4 + this.optLength; 217 + int len = MINIMUM_OPTION_LEN_BYTES + this.optLength;
136 ByteBuffer bb = ByteBuffer.allocate(len); 218 ByteBuffer bb = ByteBuffer.allocate(len);
137 bb.putShort(this.optType); 219 bb.putShort(this.optType);
138 bb.putShort(this.optLength); 220 bb.putShort(this.optLength);
......