Committed by
Gerrit Code Review
Add basic multicast RIB synchronization over REST
Change-Id: I75f22956b6b73427ca657f5ab58330b1417fdf43
Showing
3 changed files
with
94 additions
and
5 deletions
| ... | @@ -63,5 +63,10 @@ | ... | @@ -63,5 +63,10 @@ |
| 63 | <artifactId>org.osgi.compendium</artifactId> | 63 | <artifactId>org.osgi.compendium</artifactId> |
| 64 | <version>5.0.0</version> | 64 | <version>5.0.0</version> |
| 65 | </dependency> | 65 | </dependency> |
| 66 | + <dependency> | ||
| 67 | + <groupId>com.sun.jersey</groupId> | ||
| 68 | + <artifactId>jersey-client</artifactId> | ||
| 69 | + <version>1.19</version> | ||
| 70 | + </dependency> | ||
| 66 | </dependencies> | 71 | </dependencies> |
| 67 | </project> | 72 | </project> | ... | ... |
| ... | @@ -15,16 +15,25 @@ | ... | @@ -15,16 +15,25 @@ |
| 15 | */ | 15 | */ |
| 16 | package org.onosproject.cordmcast; | 16 | package org.onosproject.cordmcast; |
| 17 | 17 | ||
| 18 | +import com.fasterxml.jackson.databind.node.ObjectNode; | ||
| 18 | import com.google.common.collect.Maps; | 19 | import com.google.common.collect.Maps; |
| 20 | +import com.sun.jersey.api.client.Client; | ||
| 21 | +import com.sun.jersey.api.client.WebResource; | ||
| 22 | +import com.sun.jersey.api.client.filter.HTTPBasicAuthFilter; | ||
| 19 | import org.apache.felix.scr.annotations.Activate; | 23 | import org.apache.felix.scr.annotations.Activate; |
| 20 | import org.apache.felix.scr.annotations.Component; | 24 | import org.apache.felix.scr.annotations.Component; |
| 21 | import org.apache.felix.scr.annotations.Deactivate; | 25 | import org.apache.felix.scr.annotations.Deactivate; |
| 26 | +import org.apache.felix.scr.annotations.Modified; | ||
| 27 | +import org.apache.felix.scr.annotations.Property; | ||
| 22 | import org.apache.felix.scr.annotations.Reference; | 28 | import org.apache.felix.scr.annotations.Reference; |
| 23 | import org.apache.felix.scr.annotations.ReferenceCardinality; | 29 | import org.apache.felix.scr.annotations.ReferenceCardinality; |
| 24 | import org.onlab.packet.Ethernet; | 30 | import org.onlab.packet.Ethernet; |
| 25 | import org.onlab.packet.IPv4; | 31 | import org.onlab.packet.IPv4; |
| 26 | import org.onlab.packet.IpAddress; | 32 | import org.onlab.packet.IpAddress; |
| 27 | import org.onlab.packet.VlanId; | 33 | import org.onlab.packet.VlanId; |
| 34 | +import org.onlab.util.Tools; | ||
| 35 | +import org.onosproject.cfg.ComponentConfigService; | ||
| 36 | +import org.onosproject.codec.CodecService; | ||
| 28 | import org.onosproject.core.ApplicationId; | 37 | import org.onosproject.core.ApplicationId; |
| 29 | import org.onosproject.core.CoreService; | 38 | import org.onosproject.core.CoreService; |
| 30 | import org.onosproject.net.ConnectPoint; | 39 | import org.onosproject.net.ConnectPoint; |
| ... | @@ -42,18 +51,24 @@ import org.onosproject.net.flowobjective.ObjectiveError; | ... | @@ -42,18 +51,24 @@ import org.onosproject.net.flowobjective.ObjectiveError; |
| 42 | import org.onosproject.net.group.GroupService; | 51 | import org.onosproject.net.group.GroupService; |
| 43 | import org.onosproject.net.mcast.McastEvent; | 52 | import org.onosproject.net.mcast.McastEvent; |
| 44 | import org.onosproject.net.mcast.McastListener; | 53 | import org.onosproject.net.mcast.McastListener; |
| 54 | +import org.onosproject.net.mcast.McastRoute; | ||
| 45 | import org.onosproject.net.mcast.McastRouteInfo; | 55 | import org.onosproject.net.mcast.McastRouteInfo; |
| 46 | import org.onosproject.net.mcast.MulticastRouteService; | 56 | import org.onosproject.net.mcast.MulticastRouteService; |
| 57 | +import org.onosproject.rest.AbstractWebResource; | ||
| 58 | +import org.osgi.service.component.ComponentContext; | ||
| 47 | import org.slf4j.Logger; | 59 | import org.slf4j.Logger; |
| 48 | 60 | ||
| 61 | +import java.util.Dictionary; | ||
| 49 | import java.util.Map; | 62 | import java.util.Map; |
| 63 | +import java.util.concurrent.atomic.AtomicBoolean; | ||
| 50 | import java.util.concurrent.atomic.AtomicInteger; | 64 | import java.util.concurrent.atomic.AtomicInteger; |
| 51 | 65 | ||
| 66 | +import static com.google.common.net.MediaType.JSON_UTF_8; | ||
| 52 | import static org.slf4j.LoggerFactory.getLogger; | 67 | import static org.slf4j.LoggerFactory.getLogger; |
| 53 | 68 | ||
| 54 | /** | 69 | /** |
| 55 | * CORD multicast provisoning application. Operates by listening to | 70 | * CORD multicast provisoning application. Operates by listening to |
| 56 | - * events on the multicast rib and provsioning groups to program multicast | 71 | + * events on the multicast rib and provisioning groups to program multicast |
| 57 | * flows on the dataplane. | 72 | * flows on the dataplane. |
| 58 | */ | 73 | */ |
| 59 | @Component(immediate = true) | 74 | @Component(immediate = true) |
| ... | @@ -75,6 +90,13 @@ public class CordMcast { | ... | @@ -75,6 +90,13 @@ public class CordMcast { |
| 75 | @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) | 90 | @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) |
| 76 | protected CoreService coreService; | 91 | protected CoreService coreService; |
| 77 | 92 | ||
| 93 | + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) | ||
| 94 | + protected CodecService codecService; | ||
| 95 | + | ||
| 96 | + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) | ||
| 97 | + protected ComponentConfigService componentConfigService; | ||
| 98 | + | ||
| 99 | + | ||
| 78 | protected McastListener listener = new InternalMulticastListener(); | 100 | protected McastListener listener = new InternalMulticastListener(); |
| 79 | 101 | ||
| 80 | 102 | ||
| ... | @@ -93,20 +115,50 @@ public class CordMcast { | ... | @@ -93,20 +115,50 @@ public class CordMcast { |
| 93 | // TODO component config this | 115 | // TODO component config this |
| 94 | private int priority = DEFAULT_PRIORITY; | 116 | private int priority = DEFAULT_PRIORITY; |
| 95 | 117 | ||
| 118 | + private static final String DEFAULT_USER = "karaf"; | ||
| 119 | + private static final String DEFAULT_PASSWORD = "karaf"; | ||
| 120 | + | ||
| 121 | + @Property(name = "syncHost", value = "", | ||
| 122 | + label = "host:port to synchronize routes to") | ||
| 123 | + private String syncHost = "10.90.0.8:8181"; | ||
| 124 | + | ||
| 125 | + @Property(name = "username", value = DEFAULT_USER, | ||
| 126 | + label = "Username for REST password authentication") | ||
| 127 | + private String user = DEFAULT_USER; | ||
| 128 | + | ||
| 129 | + @Property(name = "password", value = DEFAULT_PASSWORD, | ||
| 130 | + label = "Password for REST authentication") | ||
| 131 | + private String password = DEFAULT_PASSWORD; | ||
| 132 | + | ||
| 133 | + private String fabricOnosUrl; | ||
| 134 | + | ||
| 96 | @Activate | 135 | @Activate |
| 97 | public void activate() { | 136 | public void activate() { |
| 98 | appId = coreService.registerApplication("org.onosproject.cordmcast"); | 137 | appId = coreService.registerApplication("org.onosproject.cordmcast"); |
| 138 | + componentConfigService.registerProperties(getClass()); | ||
| 99 | mcastService.addListener(listener); | 139 | mcastService.addListener(listener); |
| 140 | + | ||
| 141 | + fabricOnosUrl = "http://" + syncHost + "/onos/v1/mcast"; | ||
| 142 | + | ||
| 100 | //TODO: obtain all existing mcast routes | 143 | //TODO: obtain all existing mcast routes |
| 101 | log.info("Started"); | 144 | log.info("Started"); |
| 102 | } | 145 | } |
| 103 | 146 | ||
| 104 | @Deactivate | 147 | @Deactivate |
| 105 | public void deactivate() { | 148 | public void deactivate() { |
| 149 | + componentConfigService.unregisterProperties(getClass(), true); | ||
| 106 | mcastService.removeListener(listener); | 150 | mcastService.removeListener(listener); |
| 107 | log.info("Stopped"); | 151 | log.info("Stopped"); |
| 108 | } | 152 | } |
| 109 | 153 | ||
| 154 | + @Modified | ||
| 155 | + public void modified(ComponentContext context) { | ||
| 156 | + Dictionary<?, ?> properties = context.getProperties(); | ||
| 157 | + user = Tools.get(properties, "username"); | ||
| 158 | + password = Tools.get(properties, "password"); | ||
| 159 | + syncHost = Tools.get(properties, "syncHost"); | ||
| 160 | + } | ||
| 161 | + | ||
| 110 | private class InternalMulticastListener implements McastListener { | 162 | private class InternalMulticastListener implements McastListener { |
| 111 | @Override | 163 | @Override |
| 112 | public void event(McastEvent event) { | 164 | public void event(McastEvent event) { |
| ... | @@ -135,9 +187,10 @@ public class CordMcast { | ... | @@ -135,9 +187,10 @@ public class CordMcast { |
| 135 | } | 187 | } |
| 136 | ConnectPoint loc = info.sink().get(); | 188 | ConnectPoint loc = info.sink().get(); |
| 137 | 189 | ||
| 190 | + final AtomicBoolean sync = new AtomicBoolean(false); | ||
| 138 | 191 | ||
| 139 | Integer nextId = groups.computeIfAbsent(info.route().group(), (g) -> { | 192 | Integer nextId = groups.computeIfAbsent(info.route().group(), (g) -> { |
| 140 | - Integer id = allocateId(g); | 193 | + Integer id = allocateId(); |
| 141 | 194 | ||
| 142 | TrafficSelector mcast = DefaultTrafficSelector.builder() | 195 | TrafficSelector mcast = DefaultTrafficSelector.builder() |
| 143 | .matchVlanId(VlanId.vlanId(mcastVlan)) | 196 | .matchVlanId(VlanId.vlanId(mcastVlan)) |
| ... | @@ -170,6 +223,8 @@ public class CordMcast { | ... | @@ -170,6 +223,8 @@ public class CordMcast { |
| 170 | 223 | ||
| 171 | flowObjectiveService.forward(loc.deviceId(), fwd); | 224 | flowObjectiveService.forward(loc.deviceId(), fwd); |
| 172 | 225 | ||
| 226 | + sync.set(true); | ||
| 227 | + | ||
| 173 | return id; | 228 | return id; |
| 174 | }); | 229 | }); |
| 175 | 230 | ||
| ... | @@ -195,10 +250,37 @@ public class CordMcast { | ... | @@ -195,10 +250,37 @@ public class CordMcast { |
| 195 | }); | 250 | }); |
| 196 | 251 | ||
| 197 | flowObjectiveService.next(loc.deviceId(), next); | 252 | flowObjectiveService.next(loc.deviceId(), next); |
| 253 | + | ||
| 254 | + if (sync.get()) { | ||
| 255 | + syncRoute(info); | ||
| 256 | + } | ||
| 198 | } | 257 | } |
| 199 | 258 | ||
| 200 | - private Integer allocateId(IpAddress group) { | 259 | + private void syncRoute(McastRouteInfo info) { |
| 201 | - Integer channel = groups.putIfAbsent(group, channels.getAndIncrement()); | 260 | + if (syncHost == null) { |
| 202 | - return channel == null ? groups.get(group) : channel; | 261 | + log.warn("No host configured for synchronization; route will be dropped"); |
| 262 | + return; | ||
| 203 | } | 263 | } |
| 264 | + | ||
| 265 | + log.debug("Sending route to other ONOS: {}", info.route()); | ||
| 266 | + | ||
| 267 | + WebResource.Builder builder = getClientBuilder(fabricOnosUrl); | ||
| 268 | + | ||
| 269 | + ObjectNode json = codecService.getCodec(McastRoute.class) | ||
| 270 | + .encode(info.route(), new AbstractWebResource()); | ||
| 271 | + builder.post(json.toString()); | ||
| 272 | + } | ||
| 273 | + | ||
| 274 | + private Integer allocateId() { | ||
| 275 | + return channels.getAndIncrement(); | ||
| 276 | + } | ||
| 277 | + | ||
| 278 | + private WebResource.Builder getClientBuilder(String uri) { | ||
| 279 | + Client client = Client.create(); | ||
| 280 | + client.addFilter(new HTTPBasicAuthFilter(user, password)); | ||
| 281 | + WebResource resource = client.resource(uri); | ||
| 282 | + return resource.accept(JSON_UTF_8.toString()) | ||
| 283 | + .type(JSON_UTF_8.toString()); | ||
| 284 | + } | ||
| 285 | + | ||
| 204 | } | 286 | } | ... | ... |
| ... | @@ -58,6 +58,8 @@ | ... | @@ -58,6 +58,8 @@ |
| 58 | <bundle>mvn:com.typesafe/config/1.2.1</bundle> | 58 | <bundle>mvn:com.typesafe/config/1.2.1</bundle> |
| 59 | <bundle>mvn:org.onosproject/onlab-thirdparty/@ONOS-VERSION</bundle> | 59 | <bundle>mvn:org.onosproject/onlab-thirdparty/@ONOS-VERSION</bundle> |
| 60 | 60 | ||
| 61 | + <bundle>mvn:com.sun.jersey/jersey-client/1.19</bundle> | ||
| 62 | + | ||
| 61 | <bundle>mvn:org.mapdb/mapdb/1.0.7</bundle> | 63 | <bundle>mvn:org.mapdb/mapdb/1.0.7</bundle> |
| 62 | </feature> | 64 | </feature> |
| 63 | 65 | ... | ... |
-
Please register or login to post a comment