Jonathan Hart

Implemented multi-instance packet out.

We've defined a PacketStore abstraction through which outbound packets are
sent. The packet store has a simple implementation (basically a no-op) and a
distributed implementation on top of the cluster messaging service.

Change-Id: Ib32753314fe518ef1fd67c858db744b004539938
1 +/*
2 + * Copyright 2014 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.onlab.onos.net.packet;
17 +
18 +import org.onlab.onos.event.AbstractEvent;
19 +
20 +/**
21 + * Describes a packet event.
22 + */
23 +public class PacketEvent extends AbstractEvent<PacketEvent.Type, OutboundPacket> {
24 +
25 + /**
26 + * Type of packet events.
27 + */
28 + public enum Type {
29 + /**
30 + * Signifies that the packet should be emitted out a local port.
31 + */
32 + EMIT
33 + }
34 +
35 + /**
36 + * Creates an event of the given type for the specified packet.
37 + *
38 + * @param type the type of the event
39 + * @param packet the packet the event is about
40 + */
41 + public PacketEvent(Type type, OutboundPacket packet) {
42 + super(type, packet);
43 + }
44 +
45 + /**
46 + * Creates an event of the given type for the specified packet at the given
47 + * time.
48 + *
49 + * @param type the type of the event
50 + * @param packet the packet the event is about
51 + * @param time the time of the event
52 + */
53 + public PacketEvent(Type type, OutboundPacket packet, long time) {
54 + super(type, packet, time);
55 + }
56 +}
1 +/*
2 + * Copyright 2014 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.onlab.onos.net.packet;
17 +
18 +import org.onlab.onos.store.Store;
19 +
20 +/**
21 + * Manages routing of outbound packets.
22 + */
23 +public interface PacketStore extends Store<PacketEvent, PacketStoreDelegate> {
24 +
25 + /**
26 + * Decides which instance should emit the packet and forwards the packet to
27 + * that instance. The relevant PacketManager is notified via the
28 + * PacketStoreDelegate that it should emit the packet.
29 + *
30 + * @param packet the packet to emit
31 + */
32 + void emit(OutboundPacket packet);
33 +
34 +}
1 +/*
2 + * Copyright 2014 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.onlab.onos.net.packet;
17 +
18 +import org.onlab.onos.store.StoreDelegate;
19 +
20 +/**
21 + * Packet store delegate abstraction.
22 + */
23 +public interface PacketStoreDelegate extends StoreDelegate<PacketEvent> {
24 +}
...@@ -19,7 +19,7 @@ import static com.google.common.base.Preconditions.checkNotNull; ...@@ -19,7 +19,7 @@ import static com.google.common.base.Preconditions.checkNotNull;
19 import static org.slf4j.LoggerFactory.getLogger; 19 import static org.slf4j.LoggerFactory.getLogger;
20 20
21 import java.util.Map; 21 import java.util.Map;
22 -import java.util.TreeMap; 22 +import java.util.concurrent.ConcurrentHashMap;
23 23
24 import org.apache.felix.scr.annotations.Activate; 24 import org.apache.felix.scr.annotations.Activate;
25 import org.apache.felix.scr.annotations.Component; 25 import org.apache.felix.scr.annotations.Component;
...@@ -31,11 +31,14 @@ import org.onlab.onos.net.Device; ...@@ -31,11 +31,14 @@ import org.onlab.onos.net.Device;
31 import org.onlab.onos.net.device.DeviceService; 31 import org.onlab.onos.net.device.DeviceService;
32 import org.onlab.onos.net.packet.OutboundPacket; 32 import org.onlab.onos.net.packet.OutboundPacket;
33 import org.onlab.onos.net.packet.PacketContext; 33 import org.onlab.onos.net.packet.PacketContext;
34 +import org.onlab.onos.net.packet.PacketEvent;
34 import org.onlab.onos.net.packet.PacketProcessor; 35 import org.onlab.onos.net.packet.PacketProcessor;
35 import org.onlab.onos.net.packet.PacketProvider; 36 import org.onlab.onos.net.packet.PacketProvider;
36 import org.onlab.onos.net.packet.PacketProviderRegistry; 37 import org.onlab.onos.net.packet.PacketProviderRegistry;
37 import org.onlab.onos.net.packet.PacketProviderService; 38 import org.onlab.onos.net.packet.PacketProviderService;
38 import org.onlab.onos.net.packet.PacketService; 39 import org.onlab.onos.net.packet.PacketService;
40 +import org.onlab.onos.net.packet.PacketStore;
41 +import org.onlab.onos.net.packet.PacketStoreDelegate;
39 import org.onlab.onos.net.provider.AbstractProviderRegistry; 42 import org.onlab.onos.net.provider.AbstractProviderRegistry;
40 import org.onlab.onos.net.provider.AbstractProviderService; 43 import org.onlab.onos.net.provider.AbstractProviderService;
41 import org.slf4j.Logger; 44 import org.slf4j.Logger;
...@@ -51,18 +54,25 @@ implements PacketService, PacketProviderRegistry { ...@@ -51,18 +54,25 @@ implements PacketService, PacketProviderRegistry {
51 54
52 private final Logger log = getLogger(getClass()); 55 private final Logger log = getLogger(getClass());
53 56
57 + private final PacketStoreDelegate delegate = new InternalStoreDelegate();
58 +
54 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) 59 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
55 private DeviceService deviceService; 60 private DeviceService deviceService;
56 61
57 - private final Map<Integer, PacketProcessor> processors = new TreeMap<>(); 62 + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
63 + private PacketStore store;
64 +
65 + private final Map<Integer, PacketProcessor> processors = new ConcurrentHashMap<>();
58 66
59 @Activate 67 @Activate
60 public void activate() { 68 public void activate() {
69 + store.setDelegate(delegate);
61 log.info("Started"); 70 log.info("Started");
62 } 71 }
63 72
64 @Deactivate 73 @Deactivate
65 public void deactivate() { 74 public void deactivate() {
75 + store.unsetDelegate(delegate);
66 log.info("Stopped"); 76 log.info("Stopped");
67 } 77 }
68 78
...@@ -81,6 +91,11 @@ implements PacketService, PacketProviderRegistry { ...@@ -81,6 +91,11 @@ implements PacketService, PacketProviderRegistry {
81 @Override 91 @Override
82 public void emit(OutboundPacket packet) { 92 public void emit(OutboundPacket packet) {
83 checkNotNull(packet, "Packet cannot be null"); 93 checkNotNull(packet, "Packet cannot be null");
94 +
95 + store.emit(packet);
96 + }
97 +
98 + private void localEmit(OutboundPacket packet) {
84 final Device device = deviceService.getDevice(packet.sendThrough()); 99 final Device device = deviceService.getDevice(packet.sendThrough());
85 final PacketProvider packetProvider = getProvider(device.providerId()); 100 final PacketProvider packetProvider = getProvider(device.providerId());
86 if (packetProvider != null) { 101 if (packetProvider != null) {
...@@ -110,4 +125,16 @@ implements PacketService, PacketProviderRegistry { ...@@ -110,4 +125,16 @@ implements PacketService, PacketProviderRegistry {
110 } 125 }
111 126
112 } 127 }
128 +
129 + /**
130 + * Internal callback from the packet store.
131 + */
132 + private class InternalStoreDelegate
133 + implements PacketStoreDelegate {
134 + @Override
135 + public void notify(PacketEvent event) {
136 + localEmit(event.subject());
137 + }
138 + }
139 +
113 } 140 }
......
1 +/*
2 + * Copyright 2014 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.onlab.onos.store.packet.impl;
17 +
18 +import static org.slf4j.LoggerFactory.getLogger;
19 +
20 +import java.io.IOException;
21 +
22 +import org.apache.felix.scr.annotations.Activate;
23 +import org.apache.felix.scr.annotations.Component;
24 +import org.apache.felix.scr.annotations.Deactivate;
25 +import org.apache.felix.scr.annotations.Reference;
26 +import org.apache.felix.scr.annotations.ReferenceCardinality;
27 +import org.apache.felix.scr.annotations.Service;
28 +import org.onlab.onos.cluster.ClusterService;
29 +import org.onlab.onos.cluster.NodeId;
30 +import org.onlab.onos.mastership.MastershipService;
31 +import org.onlab.onos.net.packet.OutboundPacket;
32 +import org.onlab.onos.net.packet.PacketEvent;
33 +import org.onlab.onos.net.packet.PacketEvent.Type;
34 +import org.onlab.onos.net.packet.PacketStore;
35 +import org.onlab.onos.net.packet.PacketStoreDelegate;
36 +import org.onlab.onos.store.AbstractStore;
37 +import org.onlab.onos.store.cluster.messaging.ClusterCommunicationService;
38 +import org.onlab.onos.store.cluster.messaging.ClusterMessage;
39 +import org.onlab.onos.store.cluster.messaging.ClusterMessageHandler;
40 +import org.onlab.onos.store.cluster.messaging.MessageSubject;
41 +import org.onlab.onos.store.serializers.KryoNamespaces;
42 +import org.onlab.onos.store.serializers.KryoSerializer;
43 +import org.onlab.util.KryoNamespace;
44 +import org.slf4j.Logger;
45 +
46 +/**
47 + * Distributed packet store implementation allowing packets to be sent to
48 + * remote instances.
49 + */
50 +@Component(immediate = true)
51 +@Service
52 +public class DistributedPacketStore
53 + extends AbstractStore<PacketEvent, PacketStoreDelegate>
54 + implements PacketStore {
55 +
56 + private final Logger log = getLogger(getClass());
57 +
58 + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
59 + private MastershipService mastershipService;
60 +
61 + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
62 + private ClusterService clusterService;
63 +
64 + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
65 + private ClusterCommunicationService communicationService;
66 +
67 + private static final MessageSubject PACKET_OUT_SUBJECT =
68 + new MessageSubject("packet-out");
69 +
70 + private static final KryoSerializer SERIALIZER = new KryoSerializer() {
71 + @Override
72 + protected void setupKryoPool() {
73 + serializerPool = KryoNamespace.newBuilder()
74 + .register(KryoNamespaces.API)
75 + .build()
76 + .populate(1);
77 + }
78 + };
79 +
80 + @Activate
81 + public void activate() {
82 + log.info("Started");
83 +
84 + communicationService.addSubscriber(
85 + PACKET_OUT_SUBJECT, new InternalClusterMessageHandler());
86 + }
87 +
88 + @Deactivate
89 + public void deactivate() {
90 + log.info("Stopped");
91 + }
92 +
93 + @Override
94 + public void emit(OutboundPacket packet) {
95 + NodeId myId = clusterService.getLocalNode().id();
96 + NodeId master = mastershipService.getMasterFor(packet.sendThrough());
97 +
98 + if (myId.equals(master)) {
99 + notifyDelegate(new PacketEvent(Type.EMIT, packet));
100 + return;
101 + }
102 +
103 + try {
104 + communicationService.unicast(new ClusterMessage(
105 + myId, PACKET_OUT_SUBJECT, SERIALIZER.encode(packet)), master);
106 + } catch (IOException e) {
107 + log.warn("Failed to send packet-out to {}", master);
108 + }
109 + }
110 +
111 + /**
112 + * Handles incoming cluster messages.
113 + */
114 + private class InternalClusterMessageHandler implements ClusterMessageHandler {
115 + @Override
116 + public void handle(ClusterMessage message) {
117 + if (!message.subject().equals(PACKET_OUT_SUBJECT)) {
118 + log.warn("Received message with wrong subject: {}", message);
119 + }
120 +
121 + OutboundPacket packet = SERIALIZER.decode(message.payload());
122 + notifyDelegate(new PacketEvent(Type.EMIT, packet));
123 + }
124 + }
125 +
126 +}
1 +/**
2 + * Implementation of distributed packet store.
3 + */
4 +package org.onlab.onos.store.packet.impl;
...\ No newline at end of file ...\ No newline at end of file
1 +/*
2 + * Copyright 2014 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.onlab.onos.store.serializers;
17 +
18 +import java.nio.ByteBuffer;
19 +
20 +import org.onlab.onos.net.DeviceId;
21 +import org.onlab.onos.net.flow.TrafficTreatment;
22 +import org.onlab.onos.net.packet.DefaultOutboundPacket;
23 +
24 +import com.esotericsoftware.kryo.Kryo;
25 +import com.esotericsoftware.kryo.Serializer;
26 +import com.esotericsoftware.kryo.io.Input;
27 +import com.esotericsoftware.kryo.io.Output;
28 +
29 +/**
30 + * Serializer for a default outbound packet.
31 + */
32 +public class DefaultOutboundPacketSerializer extends Serializer<DefaultOutboundPacket> {
33 +
34 + /**
35 + * Creates {@link DefaultOutboundPacket} serializer instance.
36 + */
37 + public DefaultOutboundPacketSerializer() {
38 + // non-null, immutable
39 + super(false, true);
40 + }
41 +
42 + @Override
43 + public DefaultOutboundPacket read(Kryo kryo, Input input,
44 + Class<DefaultOutboundPacket> type) {
45 + DeviceId sendThrough = (DeviceId) kryo.readClassAndObject(input);
46 + TrafficTreatment treatment = (TrafficTreatment) kryo.readClassAndObject(input);
47 + byte[] data = (byte[]) kryo.readClassAndObject(input);
48 + return new DefaultOutboundPacket(sendThrough, treatment, ByteBuffer.wrap(data));
49 + }
50 +
51 + @Override
52 + public void write(Kryo kryo, Output output, DefaultOutboundPacket object) {
53 + kryo.writeClassAndObject(output, object.sendThrough());
54 + kryo.writeClassAndObject(output, object.treatment());
55 + kryo.writeClassAndObject(output, object.data().array());
56 + }
57 +
58 +}
...@@ -74,6 +74,7 @@ import org.onlab.onos.net.intent.MultiPointToSinglePointIntent; ...@@ -74,6 +74,7 @@ import org.onlab.onos.net.intent.MultiPointToSinglePointIntent;
74 import org.onlab.onos.net.intent.PathIntent; 74 import org.onlab.onos.net.intent.PathIntent;
75 import org.onlab.onos.net.intent.PointToPointIntent; 75 import org.onlab.onos.net.intent.PointToPointIntent;
76 import org.onlab.onos.net.link.DefaultLinkDescription; 76 import org.onlab.onos.net.link.DefaultLinkDescription;
77 +import org.onlab.onos.net.packet.DefaultOutboundPacket;
77 import org.onlab.onos.net.provider.ProviderId; 78 import org.onlab.onos.net.provider.ProviderId;
78 import org.onlab.onos.store.Timestamp; 79 import org.onlab.onos.store.Timestamp;
79 import org.onlab.packet.ChassisId; 80 import org.onlab.packet.ChassisId;
...@@ -115,6 +116,7 @@ public final class KryoNamespaces { ...@@ -115,6 +116,7 @@ public final class KryoNamespaces {
115 HashMap.class, 116 HashMap.class,
116 HashSet.class, 117 HashSet.class,
117 LinkedList.class, 118 LinkedList.class,
119 + byte[].class,
118 // 120 //
119 // 121 //
120 ControllerNode.State.class, 122 ControllerNode.State.class,
...@@ -194,6 +196,7 @@ public final class KryoNamespaces { ...@@ -194,6 +196,7 @@ public final class KryoNamespaces {
194 .register(DefaultLink.class, new DefaultLinkSerializer()) 196 .register(DefaultLink.class, new DefaultLinkSerializer())
195 .register(MastershipTerm.class, new MastershipTermSerializer()) 197 .register(MastershipTerm.class, new MastershipTermSerializer())
196 .register(HostLocation.class, new HostLocationSerializer()) 198 .register(HostLocation.class, new HostLocationSerializer())
199 + .register(DefaultOutboundPacket.class, new DefaultOutboundPacketSerializer())
197 200
198 .build(); 201 .build();
199 202
......
...@@ -15,9 +15,10 @@ ...@@ -15,9 +15,10 @@
15 */ 15 */
16 package org.onlab.onos.store.serializers; 16 package org.onlab.onos.store.serializers;
17 17
18 -import org.onlab.util.KryoNamespace;
19 import java.nio.ByteBuffer; 18 import java.nio.ByteBuffer;
20 19
20 +import org.onlab.util.KryoNamespace;
21 +
21 /** 22 /**
22 * StoreSerializer implementation using Kryo. 23 * StoreSerializer implementation using Kryo.
23 */ 24 */
...@@ -30,7 +31,7 @@ public class KryoSerializer implements StoreSerializer { ...@@ -30,7 +31,7 @@ public class KryoSerializer implements StoreSerializer {
30 } 31 }
31 32
32 /** 33 /**
33 - * Sets up the common serialzers pool. 34 + * Sets up the common serializers pool.
34 */ 35 */
35 protected void setupKryoPool() { 36 protected void setupKryoPool() {
36 serializerPool = KryoNamespace.newBuilder() 37 serializerPool = KryoNamespace.newBuilder()
......
1 +/*
2 + * Copyright 2014 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.onlab.onos.store.trivial.impl;
17 +
18 +import org.apache.felix.scr.annotations.Component;
19 +import org.apache.felix.scr.annotations.Service;
20 +import org.onlab.onos.net.packet.OutboundPacket;
21 +import org.onlab.onos.net.packet.PacketEvent;
22 +import org.onlab.onos.net.packet.PacketEvent.Type;
23 +import org.onlab.onos.net.packet.PacketStore;
24 +import org.onlab.onos.net.packet.PacketStoreDelegate;
25 +import org.onlab.onos.store.AbstractStore;
26 +
27 +/**
28 + * Simple single instance implementation of the packet store.
29 + */
30 +@Component(immediate = true)
31 +@Service
32 +public class SimplePacketStore
33 + extends AbstractStore<PacketEvent, PacketStoreDelegate>
34 + implements PacketStore {
35 +
36 + @Override
37 + public void emit(OutboundPacket packet) {
38 + notifyDelegate(new PacketEvent(Type.EMIT, packet));
39 + }
40 +
41 +}
...@@ -115,10 +115,10 @@ public final class KryoNamespace implements KryoFactory { ...@@ -115,10 +115,10 @@ public final class KryoNamespace implements KryoFactory {
115 /** 115 /**
116 * Creates a Kryo instance pool. 116 * Creates a Kryo instance pool.
117 * 117 *
118 - * @param registerdTypes types to register 118 + * @param registeredTypes types to register
119 */ 119 */
120 - private KryoNamespace(final List<Pair<Class<?>, Serializer<?>>> registerdTypes) { 120 + private KryoNamespace(final List<Pair<Class<?>, Serializer<?>>> registeredTypes) {
121 - this.registeredTypes = ImmutableList.copyOf(registerdTypes); 121 + this.registeredTypes = ImmutableList.copyOf(registeredTypes);
122 // always true for now 122 // always true for now
123 this.registrationRequired = true; 123 this.registrationRequired = true;
124 } 124 }
......