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
382 additions
and
15 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. |
| ... | @@ -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 | ... | ... |
-
Please register or login to post a comment