Hyunsun Moon
Committed by Gerrit Code Review

CORD-537 Added flow rules for vSG connectivity

- Added Q_IN_Q table
- Added flow rules for vSG connectivity
- Changed to listen port update event from Neutron to update vSG IPs

Change-Id: I227ba7a91e90ec0752481ebf623b4e848d585265
...@@ -38,7 +38,6 @@ import org.onosproject.net.Host; ...@@ -38,7 +38,6 @@ import org.onosproject.net.Host;
38 import org.onosproject.net.HostId; 38 import org.onosproject.net.HostId;
39 import org.onosproject.net.HostLocation; 39 import org.onosproject.net.HostLocation;
40 import org.onosproject.net.Port; 40 import org.onosproject.net.Port;
41 -import org.onosproject.net.SparseAnnotations;
42 import org.onosproject.net.config.ConfigFactory; 41 import org.onosproject.net.config.ConfigFactory;
43 import org.onosproject.net.config.NetworkConfigEvent; 42 import org.onosproject.net.config.NetworkConfigEvent;
44 import org.onosproject.net.config.NetworkConfigListener; 43 import org.onosproject.net.config.NetworkConfigListener;
...@@ -137,10 +136,14 @@ public class CordVtn extends AbstractProvider implements CordVtnService, HostPro ...@@ -137,10 +136,14 @@ public class CordVtn extends AbstractProvider implements CordVtnService, HostPro
137 }; 136 };
138 137
139 private static final String DEFAULT_TUNNEL = "vxlan"; 138 private static final String DEFAULT_TUNNEL = "vxlan";
140 - private static final Ip4Address DEFAULT_DNS = Ip4Address.valueOf("8.8.8.8");
141 private static final String SERVICE_ID = "serviceId"; 139 private static final String SERVICE_ID = "serviceId";
142 - private static final String LOCATION_IP = "locationIp";
143 private static final String OPENSTACK_VM_ID = "openstackVmId"; 140 private static final String OPENSTACK_VM_ID = "openstackVmId";
141 + private static final String OPENSTACK_PORT_ID = "openstackPortId";
142 + private static final String DATA_PLANE_IP = "dataPlaneIp";
143 + private static final String DATA_PLANE_INTF = "dataPlaneIntf";
144 + private static final String S_TAG = "stag";
145 +
146 + private static final Ip4Address DEFAULT_DNS = Ip4Address.valueOf("8.8.8.8");
144 147
145 private final ExecutorService eventExecutor = 148 private final ExecutorService eventExecutor =
146 newSingleThreadScheduledExecutor(groupedThreads("onos/cordvtn", "event-handler")); 149 newSingleThreadScheduledExecutor(groupedThreads("onos/cordvtn", "event-handler"));
...@@ -263,18 +266,24 @@ public class CordVtn extends AbstractProvider implements CordVtnService, HostPro ...@@ -263,18 +266,24 @@ public class CordVtn extends AbstractProvider implements CordVtnService, HostPro
263 } 266 }
264 267
265 Set<IpAddress> ip = Sets.newHashSet(vPort.fixedIps().values()); 268 Set<IpAddress> ip = Sets.newHashSet(vPort.fixedIps().values());
266 - SparseAnnotations annotations = DefaultAnnotations.builder() 269 + DefaultAnnotations.Builder annotations = DefaultAnnotations.builder()
267 - .set(OPENSTACK_VM_ID, vPort.deviceId())
268 .set(SERVICE_ID, vPort.networkId()) 270 .set(SERVICE_ID, vPort.networkId())
269 - .set(LOCATION_IP, node.dpIp().ip().toString()) 271 + .set(OPENSTACK_VM_ID, vPort.deviceId())
270 - .build(); 272 + .set(OPENSTACK_PORT_ID, vPort.id())
273 + .set(DATA_PLANE_IP, node.dpIp().ip().toString())
274 + .set(DATA_PLANE_INTF, node.dpIntf());
275 +
276 + String serviceVlan = getServiceVlan(vPort);
277 + if (serviceVlan != null) {
278 + annotations.set(S_TAG, serviceVlan);
279 + }
271 280
272 HostDescription hostDesc = new DefaultHostDescription( 281 HostDescription hostDesc = new DefaultHostDescription(
273 mac, 282 mac,
274 VlanId.NONE, 283 VlanId.NONE,
275 new HostLocation(connectPoint, System.currentTimeMillis()), 284 new HostLocation(connectPoint, System.currentTimeMillis()),
276 ip, 285 ip,
277 - annotations); 286 + annotations.build());
278 287
279 hostProvider.hostDetected(hostId, hostDesc, false); 288 hostProvider.hostDetected(hostId, hostDesc, false);
280 } 289 }
...@@ -294,6 +303,20 @@ public class CordVtn extends AbstractProvider implements CordVtnService, HostPro ...@@ -294,6 +303,20 @@ public class CordVtn extends AbstractProvider implements CordVtnService, HostPro
294 hostProvider.hostVanished(host.id()); 303 hostProvider.hostVanished(host.id());
295 } 304 }
296 305
306 + @Override
307 + public void updateVirtualSubscriberGateways(HostId vSgHostId, String serviceVlan,
308 + Set<IpAddress> vSgIps) {
309 + Host vSgVm = hostService.getHost(vSgHostId);
310 +
311 + if (vSgVm == null || !vSgVm.annotations().value(S_TAG).equals(serviceVlan)) {
312 + log.debug("Invalid vSG updates for {}", serviceVlan);
313 + return;
314 + }
315 +
316 + log.info("Updates vSGs in {} with {}", vSgVm.id(), vSgIps.toString());
317 + ruleInstaller.populateSubscriberGatewayRules(vSgVm, vSgIps);
318 + }
319 +
297 /** 320 /**
298 * Returns CordService by service ID. 321 * Returns CordService by service ID.
299 * 322 *
...@@ -357,10 +380,11 @@ public class CordVtn extends AbstractProvider implements CordVtnService, HostPro ...@@ -357,10 +380,11 @@ public class CordVtn extends AbstractProvider implements CordVtnService, HostPro
357 * Returns IP address for tunneling for a given host. 380 * Returns IP address for tunneling for a given host.
358 * 381 *
359 * @param host host 382 * @param host host
360 - * @return ip address 383 + * @return ip address, or null
361 */ 384 */
362 private IpAddress getTunnelIp(Host host) { 385 private IpAddress getTunnelIp(Host host) {
363 - return IpAddress.valueOf(host.annotations().value(LOCATION_IP)); 386 + String ip = host.annotations().value(DATA_PLANE_IP);
387 + return ip == null ? null : IpAddress.valueOf(ip);
364 } 388 }
365 389
366 /** 390 /**
...@@ -374,6 +398,22 @@ public class CordVtn extends AbstractProvider implements CordVtnService, HostPro ...@@ -374,6 +398,22 @@ public class CordVtn extends AbstractProvider implements CordVtnService, HostPro
374 } 398 }
375 399
376 /** 400 /**
401 + * Returns s-tag from a given OpenStack port.
402 + *
403 + * @param vPort openstack port
404 + * @return s-tag string
405 + */
406 + private String getServiceVlan(OpenstackPort vPort) {
407 + checkNotNull(vPort);
408 +
409 + if (vPort.name() != null && vPort.name().startsWith(S_TAG)) {
410 + return vPort.name().split("-")[1];
411 + } else {
412 + return null;
413 + }
414 + }
415 +
416 + /**
377 * Returns hosts associated with a given OpenStack network. 417 * Returns hosts associated with a given OpenStack network.
378 * 418 *
379 * @param vNet openstack network 419 * @param vNet openstack network
...@@ -395,6 +435,30 @@ public class CordVtn extends AbstractProvider implements CordVtnService, HostPro ...@@ -395,6 +435,30 @@ public class CordVtn extends AbstractProvider implements CordVtnService, HostPro
395 } 435 }
396 436
397 /** 437 /**
438 + * Returns public ip addresses of vSGs running inside a give vSG host.
439 + *
440 + * @param vSgHost vSG host
441 + * @return set of ip address, or empty set
442 + */
443 + private Set<IpAddress> getSubscriberGatewayIps(Host vSgHost) {
444 + String vPortId = vSgHost.annotations().value(OPENSTACK_PORT_ID);
445 + String serviceVlan = vSgHost.annotations().value(S_TAG);
446 +
447 + OpenstackPort vPort = openstackService.port(vPortId);
448 + if (vPort == null) {
449 + log.warn("Failed to get OpenStack port {} for VM {}", vPortId, vSgHost.id());
450 + return Sets.newHashSet();
451 + }
452 +
453 + if (!serviceVlan.equals(getServiceVlan(vPort))) {
454 + log.error("Host({}) s-tag does not match with vPort s-tag", vSgHost.id());
455 + return Sets.newHashSet();
456 + }
457 +
458 + return vPort.allowedAddressPairs().keySet();
459 + }
460 +
461 + /**
398 * Registers static DHCP lease for a given host. 462 * Registers static DHCP lease for a given host.
399 * 463 *
400 * @param host host 464 * @param host host
...@@ -452,8 +516,13 @@ public class CordVtn extends AbstractProvider implements CordVtnService, HostPro ...@@ -452,8 +516,13 @@ public class CordVtn extends AbstractProvider implements CordVtnService, HostPro
452 arpProxy.sendGratuitousArp(service.serviceIp(), gatewayMac, Sets.newHashSet(host)); 516 arpProxy.sendGratuitousArp(service.serviceIp(), gatewayMac, Sets.newHashSet(host));
453 } 517 }
454 518
455 - ruleInstaller.populateBasicConnectionRules(host, getTunnelIp(host), vNet);
456 registerDhcpLease(host, service); 519 registerDhcpLease(host, service);
520 + ruleInstaller.populateBasicConnectionRules(host, getTunnelIp(host), vNet);
521 +
522 + if (host.annotations().value(S_TAG) != null) {
523 + log.debug("vSG VM detected {}", host.id());
524 + ruleInstaller.populateSubscriberGatewayRules(host, getSubscriberGatewayIps(host));
525 + }
457 } 526 }
458 527
459 /** 528 /**
...@@ -468,7 +537,7 @@ public class CordVtn extends AbstractProvider implements CordVtnService, HostPro ...@@ -468,7 +537,7 @@ public class CordVtn extends AbstractProvider implements CordVtnService, HostPro
468 } 537 }
469 538
470 String vNetId = host.annotations().value(SERVICE_ID); 539 String vNetId = host.annotations().value(SERVICE_ID);
471 - OpenstackNetwork vNet = openstackService.network(host.annotations().value(SERVICE_ID)); 540 + OpenstackNetwork vNet = openstackService.network(vNetId);
472 if (vNet == null) { 541 if (vNet == null) {
473 log.warn("Failed to get OpenStack network {} for VM {}({}).", 542 log.warn("Failed to get OpenStack network {} for VM {}({}).",
474 vNetId, 543 vNetId,
......
...@@ -15,7 +15,11 @@ ...@@ -15,7 +15,11 @@
15 */ 15 */
16 package org.onosproject.cordvtn; 16 package org.onosproject.cordvtn;
17 17
18 +import org.onlab.packet.IpAddress;
18 import org.onosproject.net.ConnectPoint; 19 import org.onosproject.net.ConnectPoint;
20 +import org.onosproject.net.HostId;
21 +
22 +import java.util.Set;
19 23
20 /** 24 /**
21 * Service for provisioning overlay virtual networks on compute nodes. 25 * Service for provisioning overlay virtual networks on compute nodes.
...@@ -57,4 +61,14 @@ public interface CordVtnService { ...@@ -57,4 +61,14 @@ public interface CordVtnService {
57 * @param pServiceId id of the service which provide dependency 61 * @param pServiceId id of the service which provide dependency
58 */ 62 */
59 void removeServiceDependency(CordServiceId tServiceId, CordServiceId pServiceId); 63 void removeServiceDependency(CordServiceId tServiceId, CordServiceId pServiceId);
64 +
65 + /**
66 + * Updates virtual service gateways.
67 + *
68 + * @param vSgHost host id of vSG host
69 + * @param serviceVlan service vlan id
70 + * @param vSgIps set of ip address of vSGs running in this vSG host
71 + */
72 + void updateVirtualSubscriberGateways(HostId vSgHost, String serviceVlan,
73 + Set<IpAddress> vSgIps);
60 } 74 }
......
...@@ -220,7 +220,7 @@ public final class RemoteIpCommandUtil { ...@@ -220,7 +220,7 @@ public final class RemoteIpCommandUtil {
220 return null; 220 return null;
221 } 221 }
222 222
223 - log.debug("Execute command {} to {}", command, session.getHost()); 223 + log.trace("Execute command {} to {}", command, session.getHost());
224 224
225 try { 225 try {
226 Channel channel = session.openChannel("exec"); 226 Channel channel = session.openChannel("exec");
......
...@@ -15,6 +15,13 @@ ...@@ -15,6 +15,13 @@
15 */ 15 */
16 package org.onosproject.cordvtn.rest; 16 package org.onosproject.cordvtn.rest;
17 17
18 +import com.fasterxml.jackson.databind.JsonNode;
19 +import com.fasterxml.jackson.databind.ObjectMapper;
20 +import com.google.common.collect.Sets;
21 +import org.onlab.packet.IpAddress;
22 +import org.onlab.packet.MacAddress;
23 +import org.onosproject.cordvtn.CordVtnService;
24 +import org.onosproject.net.HostId;
18 import org.onosproject.rest.AbstractWebResource; 25 import org.onosproject.rest.AbstractWebResource;
19 import org.slf4j.Logger; 26 import org.slf4j.Logger;
20 import org.slf4j.LoggerFactory; 27 import org.slf4j.LoggerFactory;
...@@ -29,16 +36,29 @@ import javax.ws.rs.Produces; ...@@ -29,16 +36,29 @@ import javax.ws.rs.Produces;
29 import javax.ws.rs.core.MediaType; 36 import javax.ws.rs.core.MediaType;
30 import javax.ws.rs.core.Response; 37 import javax.ws.rs.core.Response;
31 import java.io.InputStream; 38 import java.io.InputStream;
39 +import java.util.Set;
40 +
32 41
33 /** 42 /**
34 * Dummy Neutron ML2 mechanism driver. 43 * Dummy Neutron ML2 mechanism driver.
35 - * It just returns OK for ports resource requests. 44 + * It just returns OK for ports resource requests except for the port update.
36 */ 45 */
37 @Path("ports") 46 @Path("ports")
38 public class NeutronMl2PortsWebResource extends AbstractWebResource { 47 public class NeutronMl2PortsWebResource extends AbstractWebResource {
39 protected final Logger log = LoggerFactory.getLogger(getClass()); 48 protected final Logger log = LoggerFactory.getLogger(getClass());
40 private static final String PORTS_MESSAGE = "Received ports %s"; 49 private static final String PORTS_MESSAGE = "Received ports %s";
41 50
51 + private static final String PORT = "port";
52 + private static final String DEVICE_ID = "device_id";
53 + private static final String NAME = "name";
54 + private static final String MAC_ADDRESS = "mac_address";
55 + private static final String ADDRESS_PAIRS = "allowed_address_pairs";
56 + private static final String IP_ADDERSS = "ip_address";
57 + private static final String STAG_PREFIX = "stag-";
58 + private static final int STAG_BEGIN_INDEX = 5;
59 +
60 + private final CordVtnService service = get(CordVtnService.class);
61 +
42 @POST 62 @POST
43 @Consumes(MediaType.APPLICATION_JSON) 63 @Consumes(MediaType.APPLICATION_JSON)
44 @Produces(MediaType.APPLICATION_JSON) 64 @Produces(MediaType.APPLICATION_JSON)
...@@ -53,6 +73,35 @@ public class NeutronMl2PortsWebResource extends AbstractWebResource { ...@@ -53,6 +73,35 @@ public class NeutronMl2PortsWebResource extends AbstractWebResource {
53 @Produces(MediaType.APPLICATION_JSON) 73 @Produces(MediaType.APPLICATION_JSON)
54 public Response updatePorts(@PathParam("id") String id, InputStream input) { 74 public Response updatePorts(@PathParam("id") String id, InputStream input) {
55 log.debug(String.format(PORTS_MESSAGE, "update")); 75 log.debug(String.format(PORTS_MESSAGE, "update"));
76 +
77 + try {
78 + ObjectMapper mapper = new ObjectMapper();
79 + JsonNode jsonNode = mapper.readTree(input).get(PORT);
80 + log.trace("{}", jsonNode.toString());
81 +
82 + String deviceId = jsonNode.path(DEVICE_ID).asText();
83 + String name = jsonNode.path(NAME).asText();
84 + if (deviceId.isEmpty() || name.isEmpty() || !name.startsWith(STAG_PREFIX)) {
85 + // ignore all updates other than allowed address pairs
86 + return Response.status(Response.Status.OK).build();
87 + }
88 +
89 + // this is allowed address pairs updates
90 + MacAddress mac = MacAddress.valueOf(jsonNode.path(MAC_ADDRESS).asText());
91 + Set<IpAddress> vSgIps = Sets.newHashSet();
92 + jsonNode.path(ADDRESS_PAIRS).forEach(addrPair -> {
93 + IpAddress ip = IpAddress.valueOf(addrPair.path(IP_ADDERSS).asText());
94 + vSgIps.add(ip);
95 + });
96 +
97 + service.updateVirtualSubscriberGateways(
98 + HostId.hostId(mac),
99 + name.substring(STAG_BEGIN_INDEX),
100 + vSgIps);
101 + } catch (Exception e) {
102 + return Response.status(Response.Status.INTERNAL_SERVER_ERROR).build();
103 + }
104 +
56 return Response.status(Response.Status.OK).build(); 105 return Response.status(Response.Status.OK).build();
57 } 106 }
58 107
......