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,
......
...@@ -25,6 +25,7 @@ import org.onlab.packet.IpAddress; ...@@ -25,6 +25,7 @@ import org.onlab.packet.IpAddress;
25 import org.onlab.packet.IpPrefix; 25 import org.onlab.packet.IpPrefix;
26 import org.onlab.packet.MacAddress; 26 import org.onlab.packet.MacAddress;
27 import org.onlab.packet.TpPort; 27 import org.onlab.packet.TpPort;
28 +import org.onlab.packet.VlanId;
28 import org.onlab.util.ItemNotFoundException; 29 import org.onlab.util.ItemNotFoundException;
29 import org.onosproject.core.ApplicationId; 30 import org.onosproject.core.ApplicationId;
30 import org.onosproject.core.DefaultGroupId; 31 import org.onosproject.core.DefaultGroupId;
...@@ -59,6 +60,7 @@ import org.onosproject.net.flow.instructions.ExtensionPropertyException; ...@@ -59,6 +60,7 @@ import org.onosproject.net.flow.instructions.ExtensionPropertyException;
59 import org.onosproject.net.flow.instructions.ExtensionTreatment; 60 import org.onosproject.net.flow.instructions.ExtensionTreatment;
60 import org.onosproject.net.flow.instructions.Instruction; 61 import org.onosproject.net.flow.instructions.Instruction;
61 import org.onosproject.net.flow.instructions.Instructions; 62 import org.onosproject.net.flow.instructions.Instructions;
63 +import org.onosproject.net.flow.instructions.L2ModificationInstruction;
62 import org.onosproject.net.flow.instructions.L2ModificationInstruction.ModEtherInstruction; 64 import org.onosproject.net.flow.instructions.L2ModificationInstruction.ModEtherInstruction;
63 import org.onosproject.net.group.DefaultGroupBucket; 65 import org.onosproject.net.group.DefaultGroupBucket;
64 import org.onosproject.net.group.DefaultGroupDescription; 66 import org.onosproject.net.group.DefaultGroupDescription;
...@@ -87,6 +89,7 @@ import static org.onosproject.net.flow.criteria.Criterion.Type.IPV4_DST; ...@@ -87,6 +89,7 @@ import static org.onosproject.net.flow.criteria.Criterion.Type.IPV4_DST;
87 import static org.onosproject.net.flow.criteria.Criterion.Type.IPV4_SRC; 89 import static org.onosproject.net.flow.criteria.Criterion.Type.IPV4_SRC;
88 import static org.onosproject.net.flow.instructions.ExtensionTreatmentType.ExtensionTreatmentTypes.NICIRA_SET_TUNNEL_DST; 90 import static org.onosproject.net.flow.instructions.ExtensionTreatmentType.ExtensionTreatmentTypes.NICIRA_SET_TUNNEL_DST;
89 import static org.onosproject.net.flow.instructions.L2ModificationInstruction.L2SubType.ETH_DST; 91 import static org.onosproject.net.flow.instructions.L2ModificationInstruction.L2SubType.ETH_DST;
92 +import static org.onosproject.net.flow.instructions.L2ModificationInstruction.L2SubType.VLAN_PUSH;
90 import static org.slf4j.LoggerFactory.getLogger; 93 import static org.slf4j.LoggerFactory.getLogger;
91 94
92 /** 95 /**
...@@ -96,21 +99,27 @@ public class CordVtnRuleInstaller { ...@@ -96,21 +99,27 @@ public class CordVtnRuleInstaller {
96 99
97 protected final Logger log = getLogger(getClass()); 100 protected final Logger log = getLogger(getClass());
98 101
99 - private static final String PORT_NAME = "portName";
100 private static final int TABLE_FIRST = 0; 102 private static final int TABLE_FIRST = 0;
101 private static final int TABLE_IN_PORT = 1; 103 private static final int TABLE_IN_PORT = 1;
102 private static final int TABLE_ACCESS_TYPE = 2; 104 private static final int TABLE_ACCESS_TYPE = 2;
103 private static final int TABLE_IN_SERVICE = 3; 105 private static final int TABLE_IN_SERVICE = 3;
104 private static final int TABLE_DST_IP = 4; 106 private static final int TABLE_DST_IP = 4;
105 private static final int TABLE_TUNNEL_IN = 5; 107 private static final int TABLE_TUNNEL_IN = 5;
108 + private static final int TABLE_Q_IN_Q = 6;
106 109
107 private static final int MANAGEMENT_PRIORITY = 55000; 110 private static final int MANAGEMENT_PRIORITY = 55000;
111 + private static final int VSG_PRIORITY = 55000;
108 private static final int HIGH_PRIORITY = 50000; 112 private static final int HIGH_PRIORITY = 50000;
109 private static final int DEFAULT_PRIORITY = 5000; 113 private static final int DEFAULT_PRIORITY = 5000;
110 private static final int LOW_PRIORITY = 4000; 114 private static final int LOW_PRIORITY = 4000;
111 private static final int LOWEST_PRIORITY = 0; 115 private static final int LOWEST_PRIORITY = 0;
112 116
113 private static final int VXLAN_UDP_PORT = 4789; 117 private static final int VXLAN_UDP_PORT = 4789;
118 + private static final VlanId VLAN_WAN = VlanId.vlanId((short) 500);
119 +
120 + private static final String PORT_NAME = "portName";
121 + private static final String DATA_PLANE_INTF = "dataPlaneIntf";
122 + private static final String S_TAG = "stag";
114 123
115 private final ApplicationId appId; 124 private final ApplicationId appId;
116 private final FlowRuleService flowRuleService; 125 private final FlowRuleService flowRuleService;
...@@ -163,6 +172,7 @@ public class CordVtnRuleInstaller { ...@@ -163,6 +172,7 @@ public class CordVtnRuleInstaller {
163 processFirstTable(deviceId, dpPort, dpIp); 172 processFirstTable(deviceId, dpPort, dpIp);
164 processInPortTable(deviceId, tunnelPort, dpPort); 173 processInPortTable(deviceId, tunnelPort, dpPort);
165 processAccessTypeTable(deviceId, dpPort); 174 processAccessTypeTable(deviceId, dpPort);
175 + processQInQTable(deviceId, dpPort);
166 } 176 }
167 177
168 /** 178 /**
...@@ -406,6 +416,10 @@ public class CordVtnRuleInstaller { ...@@ -406,6 +416,10 @@ public class CordVtnRuleInstaller {
406 DeviceId deviceId = host.location().deviceId(); 416 DeviceId deviceId = host.location().deviceId();
407 IpAddress hostIp = host.ipAddresses().stream().findFirst().get(); 417 IpAddress hostIp = host.ipAddresses().stream().findFirst().get();
408 418
419 + if (!mastershipService.isLocalMaster(deviceId)) {
420 + return;
421 + }
422 +
409 TrafficSelector selector = DefaultTrafficSelector.builder() 423 TrafficSelector selector = DefaultTrafficSelector.builder()
410 .matchEthType(Ethernet.TYPE_ARP) 424 .matchEthType(Ethernet.TYPE_ARP)
411 .matchArpTpa(mService.serviceIp().getIp4Address()) 425 .matchArpTpa(mService.serviceIp().getIp4Address())
...@@ -502,6 +516,10 @@ public class CordVtnRuleInstaller { ...@@ -502,6 +516,10 @@ public class CordVtnRuleInstaller {
502 public void removeManagementNetworkRules(Host host, CordService mService) { 516 public void removeManagementNetworkRules(Host host, CordService mService) {
503 checkNotNull(mService); 517 checkNotNull(mService);
504 518
519 + if (!mastershipService.isLocalMaster(host.location().deviceId())) {
520 + return;
521 + }
522 +
505 for (FlowRule flowRule : flowRuleService.getFlowRulesById(appId)) { 523 for (FlowRule flowRule : flowRuleService.getFlowRulesById(appId)) {
506 if (flowRule.deviceId().equals(host.location().deviceId())) { 524 if (flowRule.deviceId().equals(host.location().deviceId())) {
507 PortNumber port = getOutputFromTreatment(flowRule); 525 PortNumber port = getOutputFromTreatment(flowRule);
...@@ -515,6 +533,113 @@ public class CordVtnRuleInstaller { ...@@ -515,6 +533,113 @@ public class CordVtnRuleInstaller {
515 } 533 }
516 534
517 /** 535 /**
536 + * Populates rules for vSG VM.
537 + *
538 + * @param vSgHost vSG host
539 + * @param vSgIps set of ip addresses of vSGs running inside the vSG VM
540 + */
541 + public void populateSubscriberGatewayRules(Host vSgHost, Set<IpAddress> vSgIps) {
542 + VlanId serviceVlan = getServiceVlan(vSgHost);
543 + PortNumber dpPort = getDpPort(vSgHost);
544 +
545 + if (serviceVlan == null || dpPort == null) {
546 + log.warn("Failed to populate rules for vSG VM {}", vSgHost.id());
547 + return;
548 + }
549 +
550 + // for traffics with s-tag, strip the tag and take through the vSG VM
551 + TrafficSelector selector = DefaultTrafficSelector.builder()
552 + .matchVlanId(serviceVlan)
553 + .build();
554 +
555 + TrafficTreatment treatment = DefaultTrafficTreatment.builder()
556 + .popVlan()
557 + .setOutput(vSgHost.location().port())
558 + .build();
559 +
560 + FlowRule flowRule = DefaultFlowRule.builder()
561 + .fromApp(appId)
562 + .withSelector(selector)
563 + .withTreatment(treatment)
564 + .withPriority(DEFAULT_PRIORITY)
565 + .forDevice(vSgHost.location().deviceId())
566 + .forTable(TABLE_Q_IN_Q)
567 + .makePermanent()
568 + .build();
569 +
570 + processFlowRule(true, flowRule);
571 +
572 + // for traffics with customer vlan, tag with the service vlan based on input port with
573 + // lower priority to avoid conflict with WAN tag
574 + selector = DefaultTrafficSelector.builder()
575 + .matchInPort(vSgHost.location().port())
576 + .build();
577 +
578 + treatment = DefaultTrafficTreatment.builder()
579 + .pushVlan()
580 + .setVlanId(serviceVlan)
581 + .setOutput(dpPort)
582 + .build();
583 +
584 + flowRule = DefaultFlowRule.builder()
585 + .fromApp(appId)
586 + .withSelector(selector)
587 + .withTreatment(treatment)
588 + .withPriority(LOW_PRIORITY)
589 + .forDevice(vSgHost.location().deviceId())
590 + .forTable(TABLE_Q_IN_Q)
591 + .makePermanent()
592 + .build();
593 +
594 + processFlowRule(true, flowRule);
595 +
596 + // for traffic coming from WAN, tag 500 and take through the vSG VM
597 + // based on destination ip
598 + vSgIps.stream().forEach(ip -> {
599 + TrafficSelector downstream = DefaultTrafficSelector.builder()
600 + .matchEthType(Ethernet.TYPE_IPV4)
601 + .matchIPDst(ip.toIpPrefix())
602 + .build();
603 +
604 + TrafficTreatment downstreamTreatment = DefaultTrafficTreatment.builder()
605 + .pushVlan()
606 + .setVlanId(VLAN_WAN)
607 + .setEthDst(vSgHost.mac())
608 + .setOutput(vSgHost.location().port())
609 + .build();
610 +
611 + FlowRule downstreamFlowRule = DefaultFlowRule.builder()
612 + .fromApp(appId)
613 + .withSelector(downstream)
614 + .withTreatment(downstreamTreatment)
615 + .withPriority(DEFAULT_PRIORITY)
616 + .forDevice(vSgHost.location().deviceId())
617 + .forTable(TABLE_DST_IP)
618 + .makePermanent()
619 + .build();
620 +
621 + processFlowRule(true, downstreamFlowRule);
622 + });
623 +
624 + // remove downstream flow rules for the vSG not shown in vSgIps
625 + for (FlowRule rule : flowRuleService.getFlowRulesById(appId)) {
626 + if (!rule.deviceId().equals(vSgHost.location().deviceId())) {
627 + continue;
628 + }
629 + PortNumber output = getOutputFromTreatment(rule);
630 + if (output == null || !output.equals(vSgHost.location().port()) ||
631 + !isVlanPushFromTreatment(rule)) {
632 + continue;
633 + }
634 +
635 + IpPrefix dstIp = getDstIpFromSelector(rule);
636 + if (dstIp != null && !vSgIps.contains(dstIp.address())) {
637 + processFlowRule(false, rule);
638 + }
639 + }
640 + }
641 +
642 + /**
518 * Populates default rules on the first table. 643 * Populates default rules on the first table.
519 * It includes the rules for shuttling vxlan-encapped packets between ovs and 644 * It includes the rules for shuttling vxlan-encapped packets between ovs and
520 * linux stack,and external network connectivity. 645 * linux stack,and external network connectivity.
...@@ -596,6 +721,7 @@ public class CordVtnRuleInstaller { ...@@ -596,6 +721,7 @@ public class CordVtnRuleInstaller {
596 selector = DefaultTrafficSelector.builder() 721 selector = DefaultTrafficSelector.builder()
597 .matchInPort(dpPort) 722 .matchInPort(dpPort)
598 .matchEthType(Ethernet.TYPE_ARP) 723 .matchEthType(Ethernet.TYPE_ARP)
724 + .matchArpTpa(dpIp.getIp4Address())
599 .build(); 725 .build();
600 726
601 treatment = DefaultTrafficTreatment.builder() 727 treatment = DefaultTrafficTreatment.builder()
...@@ -633,6 +759,27 @@ public class CordVtnRuleInstaller { ...@@ -633,6 +759,27 @@ public class CordVtnRuleInstaller {
633 .build(); 759 .build();
634 760
635 processFlowRule(true, flowRule); 761 processFlowRule(true, flowRule);
762 +
763 + // take all vlan tagged packet to the Q_IN_Q table
764 + selector = DefaultTrafficSelector.builder()
765 + .matchVlanId(VlanId.ANY)
766 + .build();
767 +
768 + treatment = DefaultTrafficTreatment.builder()
769 + .transition(TABLE_Q_IN_Q)
770 + .build();
771 +
772 + flowRule = DefaultFlowRule.builder()
773 + .fromApp(appId)
774 + .withSelector(selector)
775 + .withTreatment(treatment)
776 + .withPriority(VSG_PRIORITY)
777 + .forDevice(deviceId)
778 + .forTable(TABLE_FIRST)
779 + .makePermanent()
780 + .build();
781 +
782 + processFlowRule(true, flowRule);
636 } 783 }
637 784
638 /** 785 /**
...@@ -716,6 +863,57 @@ public class CordVtnRuleInstaller { ...@@ -716,6 +863,57 @@ public class CordVtnRuleInstaller {
716 } 863 }
717 864
718 /** 865 /**
866 + * Populates default rules for Q_IN_Q table.
867 + *
868 + * @param deviceId device id
869 + * @param dpPort data plane interface port number
870 + */
871 + private void processQInQTable(DeviceId deviceId, PortNumber dpPort) {
872 + // for traffic going out to WAN, strip vid 500 and take through data plane interface
873 + TrafficSelector selector = DefaultTrafficSelector.builder()
874 + .matchVlanId(VLAN_WAN)
875 + .build();
876 +
877 + TrafficTreatment treatment = DefaultTrafficTreatment.builder()
878 + .popVlan()
879 + .setOutput(dpPort)
880 + .build();
881 +
882 + FlowRule flowRule = DefaultFlowRule.builder()
883 + .fromApp(appId)
884 + .withSelector(selector)
885 + .withTreatment(treatment)
886 + .withPriority(DEFAULT_PRIORITY)
887 + .forDevice(deviceId)
888 + .forTable(TABLE_Q_IN_Q)
889 + .makePermanent()
890 + .build();
891 +
892 + processFlowRule(true, flowRule);
893 +
894 + selector = DefaultTrafficSelector.builder()
895 + .matchVlanId(VLAN_WAN)
896 + .matchEthType(Ethernet.TYPE_ARP)
897 + .build();
898 +
899 + treatment = DefaultTrafficTreatment.builder()
900 + .setOutput(PortNumber.CONTROLLER)
901 + .build();
902 +
903 + flowRule = DefaultFlowRule.builder()
904 + .fromApp(appId)
905 + .withSelector(selector)
906 + .withTreatment(treatment)
907 + .withPriority(HIGH_PRIORITY)
908 + .forDevice(deviceId)
909 + .forTable(TABLE_Q_IN_Q)
910 + .makePermanent()
911 + .build();
912 +
913 + processFlowRule(true, flowRule);
914 + }
915 +
916 + /**
719 * Populates rules for local in port in IN_PORT table. 917 * Populates rules for local in port in IN_PORT table.
720 * Flows from a given in port, whose source IP is service IP transition 918 * Flows from a given in port, whose source IP is service IP transition
721 * to DST_TYPE table. Other flows transition to IN_SERVICE table. 919 * to DST_TYPE table. Other flows transition to IN_SERVICE table.
...@@ -1055,6 +1253,27 @@ public class CordVtnRuleInstaller { ...@@ -1055,6 +1253,27 @@ public class CordVtnRuleInstaller {
1055 return port == null ? null : port.number(); 1253 return port == null ? null : port.number();
1056 } 1254 }
1057 1255
1256 + /** Returns data plane interface port number of a given host.
1257 + *
1258 + * @param host host
1259 + * @return port number, or null
1260 + */
1261 + private PortNumber getDpPort(Host host) {
1262 + String portName = host.annotations().value(DATA_PLANE_INTF);
1263 + return portName == null ? null : getDpPort(host.location().deviceId(), portName);
1264 + }
1265 +
1266 + /**
1267 + * Returns service vlan from a given host.
1268 + *
1269 + * @param host host
1270 + * @return vlan id, or null
1271 + */
1272 + private VlanId getServiceVlan(Host host) {
1273 + String serviceVlan = host.annotations().value(S_TAG);
1274 + return serviceVlan == null ? null : VlanId.vlanId(Short.parseShort(serviceVlan));
1275 + }
1276 +
1058 /** 1277 /**
1059 * Returns the inport from a given flow rule if the rule contains the match of it. 1278 * Returns the inport from a given flow rule if the rule contains the match of it.
1060 * 1279 *
...@@ -1183,6 +1402,22 @@ public class CordVtnRuleInstaller { ...@@ -1183,6 +1402,22 @@ public class CordVtnRuleInstaller {
1183 } 1402 }
1184 1403
1185 /** 1404 /**
1405 + * Returns if a given flow rule has vlan push instruction or not.
1406 + *
1407 + * @param flowRule flow rule
1408 + * @return true if it includes vlan push, or false
1409 + */
1410 + private boolean isVlanPushFromTreatment(FlowRule flowRule) {
1411 + Instruction instruction = flowRule.treatment().allInstructions().stream()
1412 + .filter(inst -> inst instanceof L2ModificationInstruction)
1413 + .filter(inst -> ((L2ModificationInstruction) inst).subtype().equals(VLAN_PUSH))
1414 + .findAny()
1415 + .orElse(null);
1416 +
1417 + return instruction != null;
1418 + }
1419 +
1420 + /**
1186 * Creates a new group for a given service. 1421 * Creates a new group for a given service.
1187 * 1422 *
1188 * @param deviceId device id to create a group 1423 * @param deviceId device id to create a group
......
...@@ -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
......