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
Showing
5 changed files
with
388 additions
and
21 deletions
... | @@ -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. |
... | @@ -1033,8 +1231,8 @@ public class CordVtnRuleInstaller { | ... | @@ -1033,8 +1231,8 @@ public class CordVtnRuleInstaller { |
1033 | */ | 1231 | */ |
1034 | private PortNumber getTunnelPort(DeviceId deviceId) { | 1232 | private PortNumber getTunnelPort(DeviceId deviceId) { |
1035 | Port port = deviceService.getPorts(deviceId).stream() | 1233 | Port port = deviceService.getPorts(deviceId).stream() |
1036 | - .filter(p -> p.annotations().value(PORT_NAME).contains(tunnelType)) | 1234 | + .filter(p -> p.annotations().value(PORT_NAME).contains(tunnelType)) |
1037 | - .findFirst().orElse(null); | 1235 | + .findFirst().orElse(null); |
1038 | 1236 | ||
1039 | return port == null ? null : port.number(); | 1237 | return port == null ? null : port.number(); |
1040 | } | 1238 | } |
... | @@ -1048,13 +1246,34 @@ public class CordVtnRuleInstaller { | ... | @@ -1048,13 +1246,34 @@ public class CordVtnRuleInstaller { |
1048 | */ | 1246 | */ |
1049 | private PortNumber getDpPort(DeviceId deviceId, String dpIntf) { | 1247 | private PortNumber getDpPort(DeviceId deviceId, String dpIntf) { |
1050 | Port port = deviceService.getPorts(deviceId).stream() | 1248 | Port port = deviceService.getPorts(deviceId).stream() |
1051 | - .filter(p -> p.annotations().value(PORT_NAME).contains(dpIntf) && | 1249 | + .filter(p -> p.annotations().value(PORT_NAME).contains(dpIntf) && |
1052 | - p.isEnabled()) | 1250 | + p.isEnabled()) |
1053 | - .findFirst().orElse(null); | 1251 | + .findFirst().orElse(null); |
1054 | 1252 | ||
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 | * |
... | @@ -1171,7 +1390,7 @@ public class CordVtnRuleInstaller { | ... | @@ -1171,7 +1390,7 @@ public class CordVtnRuleInstaller { |
1171 | */ | 1390 | */ |
1172 | private PortNumber getOutputFromTreatment(FlowRule flowRule) { | 1391 | private PortNumber getOutputFromTreatment(FlowRule flowRule) { |
1173 | Instruction instruction = flowRule.treatment().allInstructions().stream() | 1392 | Instruction instruction = flowRule.treatment().allInstructions().stream() |
1174 | - .filter(inst -> inst instanceof Instructions.OutputInstruction) | 1393 | + .filter(inst -> inst instanceof Instructions.OutputInstruction) |
1175 | .findFirst() | 1394 | .findFirst() |
1176 | .orElse(null); | 1395 | .orElse(null); |
1177 | 1396 | ||
... | @@ -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 | ... | ... |
-
Please register or login to post a comment