mirror of
https://github.com/opennetworkinglab/onos.git
synced 2025-10-28 14:51:37 +01:00
Add CLI for reconfiguring ARP mode on openstacknetworking app
Change-Id: I4211681ccf6eaea9c76ec27adc45e0f1cc71d0d7
This commit is contained in:
parent
e6110b7b34
commit
7f70bb700d
@ -0,0 +1,35 @@
|
||||
/*
|
||||
* Copyright 2018-present Open Networking Foundation
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.onosproject.openstacknetworking.cli;
|
||||
|
||||
import com.google.common.collect.Lists;
|
||||
import org.onosproject.cli.AbstractChoicesCompleter;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* ARP mode completer.
|
||||
*/
|
||||
public class ArpModeCompleter extends AbstractChoicesCompleter {
|
||||
|
||||
@Override
|
||||
protected List<String> choices() {
|
||||
List<String> strings = Lists.newArrayList();
|
||||
strings.add("proxy");
|
||||
strings.add("broadcast");
|
||||
return strings;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,131 @@
|
||||
/*
|
||||
* Copyright 2018-present Open Networking Foundation
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.onosproject.openstacknetworking.cli;
|
||||
|
||||
import org.apache.karaf.shell.commands.Argument;
|
||||
import org.apache.karaf.shell.commands.Command;
|
||||
import org.onosproject.cfg.ComponentConfigService;
|
||||
import org.onosproject.cli.AbstractShellCommand;
|
||||
import org.onosproject.core.ApplicationId;
|
||||
import org.onosproject.core.CoreService;
|
||||
import org.onosproject.net.flow.FlowRuleService;
|
||||
import org.onosproject.openstacknetworking.api.Constants;
|
||||
import org.onosproject.openstacknetworking.impl.OpenstackRoutingArpHandler;
|
||||
import org.onosproject.openstacknetworking.impl.OpenstackSwitchingArpHandler;
|
||||
import org.onosproject.openstacknode.api.NodeState;
|
||||
import org.onosproject.openstacknode.api.OpenstackNode;
|
||||
import org.onosproject.openstacknode.api.OpenstackNodeAdminService;
|
||||
import org.onosproject.openstacknode.api.OpenstackNodeService;
|
||||
|
||||
import static com.google.common.base.Strings.isNullOrEmpty;
|
||||
import static org.onosproject.openstacknetworking.util.OpenstackNetworkingUtil.getPropertyValue;
|
||||
|
||||
/**
|
||||
* Configure ARP mode.
|
||||
*/
|
||||
@Command(scope = "onos", name = "openstack-config-arp-mode",
|
||||
description = "Re-configure ARP mode (proxy | broadcast)")
|
||||
public class OpenstackConfigArpModeCommand extends AbstractShellCommand {
|
||||
|
||||
private static final String ARP_MODE_NAME = "arpMode";
|
||||
private static final String PROXY_MODE = "proxy";
|
||||
private static final String BROADCAST_MODE = "broadcast";
|
||||
|
||||
@Argument(index = 0, name = "arpMode",
|
||||
description = "ARP mode (proxy | broadcast)",
|
||||
required = true, multiValued = false)
|
||||
String arpMode = null;
|
||||
|
||||
@Override
|
||||
protected void execute() {
|
||||
|
||||
if (checkArpMode(arpMode)) {
|
||||
configArpMode();
|
||||
|
||||
ComponentConfigService service = get(ComponentConfigService.class);
|
||||
String switchingComponent = OpenstackSwitchingArpHandler.class.getName();
|
||||
String routingComponent = OpenstackRoutingArpHandler.class.getName();
|
||||
|
||||
// we check the arpMode configured in each component, and purge and
|
||||
// reinstall all rules only if the arpMode is changed to the configured one
|
||||
while (true) {
|
||||
String switchingValue =
|
||||
getPropertyValue(service.getProperties(switchingComponent), ARP_MODE_NAME);
|
||||
String routingValue =
|
||||
getPropertyValue(service.getProperties(routingComponent), ARP_MODE_NAME);
|
||||
|
||||
if (arpMode.equals(switchingValue) && arpMode.equals(routingValue)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
purgeRules();
|
||||
syncRules();
|
||||
}
|
||||
}
|
||||
|
||||
private boolean checkArpMode(String arpMode) {
|
||||
|
||||
if (isNullOrEmpty(arpMode)) {
|
||||
error("ARP mode should not be empty string or null");
|
||||
return false;
|
||||
} else {
|
||||
if (arpMode.equals(PROXY_MODE) || arpMode.equals(BROADCAST_MODE)) {
|
||||
return true;
|
||||
} else {
|
||||
error("ARP mode should be either proxy or broadcast");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void purgeRules() {
|
||||
FlowRuleService flowRuleService = AbstractShellCommand.get(FlowRuleService.class);
|
||||
CoreService coreService = AbstractShellCommand.get(CoreService.class);
|
||||
ApplicationId appId = coreService.getAppId(Constants.OPENSTACK_NETWORKING_APP_ID);
|
||||
if (appId == null) {
|
||||
error("Failed to purge OpenStack networking flow rules.");
|
||||
return;
|
||||
}
|
||||
flowRuleService.removeFlowRulesById(appId);
|
||||
}
|
||||
|
||||
private void configArpMode() {
|
||||
ComponentConfigService service = get(ComponentConfigService.class);
|
||||
String switchingComponent = OpenstackSwitchingArpHandler.class.getName();
|
||||
String routingComponent = OpenstackRoutingArpHandler.class.getName();
|
||||
|
||||
if (!isNullOrEmpty(arpMode)) {
|
||||
service.setProperty(switchingComponent, ARP_MODE_NAME, arpMode);
|
||||
service.setProperty(routingComponent, ARP_MODE_NAME, arpMode);
|
||||
}
|
||||
}
|
||||
|
||||
private void syncRules() {
|
||||
// All handlers in this application reacts the node complete event and
|
||||
// tries to re-configure flow rules for the complete node.
|
||||
OpenstackNodeService osNodeService = AbstractShellCommand.get(OpenstackNodeService.class);
|
||||
OpenstackNodeAdminService osNodeAdminService = AbstractShellCommand.get(OpenstackNodeAdminService.class);
|
||||
if (osNodeService == null) {
|
||||
error("Failed to re-install flow rules for OpenStack networking.");
|
||||
return;
|
||||
}
|
||||
osNodeService.completeNodes().forEach(osNode -> {
|
||||
OpenstackNode updated = osNode.updateState(NodeState.INIT);
|
||||
osNodeAdminService.updateNode(updated);
|
||||
});
|
||||
}
|
||||
}
|
||||
@ -137,7 +137,7 @@ public class OpenstackFlowRuleManager implements OpenstackFlowRuleService {
|
||||
|
||||
@Override
|
||||
public void onError(FlowRuleOperations ops) {
|
||||
log.debug("Failed to privision vni or forwarding table");
|
||||
log.debug("Failed to provision vni or forwarding table");
|
||||
}
|
||||
}));
|
||||
}
|
||||
|
||||
@ -32,8 +32,8 @@ import org.onlab.packet.Ethernet;
|
||||
import org.onlab.packet.Ip4Address;
|
||||
import org.onlab.packet.IpAddress;
|
||||
import org.onlab.packet.MacAddress;
|
||||
import org.onlab.util.Tools;
|
||||
import org.onosproject.cfg.ComponentConfigService;
|
||||
import org.onosproject.cfg.ConfigProperty;
|
||||
import org.onosproject.cluster.ClusterService;
|
||||
import org.onosproject.cluster.LeadershipService;
|
||||
import org.onosproject.cluster.NodeId;
|
||||
@ -77,7 +77,6 @@ import org.osgi.service.component.ComponentContext;
|
||||
import org.slf4j.Logger;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.Dictionary;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
@ -97,6 +96,7 @@ import static org.onosproject.openstacknetworking.api.Constants.PRIORITY_ARP_GAT
|
||||
import static org.onosproject.openstacknetworking.util.OpenstackNetworkingUtil.associatedFloatingIp;
|
||||
import static org.onosproject.openstacknetworking.util.OpenstackNetworkingUtil.getGwByComputeDevId;
|
||||
import static org.onosproject.openstacknetworking.util.OpenstackNetworkingUtil.getGwByInstancePort;
|
||||
import static org.onosproject.openstacknetworking.util.OpenstackNetworkingUtil.getPropertyValue;
|
||||
import static org.onosproject.openstacknetworking.util.OpenstackNetworkingUtil.isAssociatedWithVM;
|
||||
import static org.onosproject.openstacknode.api.OpenstackNode.NodeType.GATEWAY;
|
||||
import static org.slf4j.LoggerFactory.getLogger;
|
||||
@ -146,8 +146,6 @@ public class OpenstackRoutingArpHandler {
|
||||
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
|
||||
protected ComponentConfigService configService;
|
||||
|
||||
// TODO: need to find a way to unify aprMode and gatewayMac variables with
|
||||
// that in SwitchingArpHandler
|
||||
@Property(name = ARP_MODE, value = DEFAULT_ARP_MODE_STR,
|
||||
label = "ARP processing mode, broadcast | proxy (default)")
|
||||
protected String arpMode = DEFAULT_ARP_MODE_STR;
|
||||
@ -205,21 +203,19 @@ public class OpenstackRoutingArpHandler {
|
||||
// that in SwitchingArpHandler
|
||||
@Modified
|
||||
void modified(ComponentContext context) {
|
||||
Dictionary<?, ?> properties = context.getProperties();
|
||||
String updateArpMode;
|
||||
|
||||
updateArpMode = Tools.get(properties, ARP_MODE);
|
||||
if (!Strings.isNullOrEmpty(updateArpMode) && !updateArpMode.equals(arpMode)) {
|
||||
arpMode = updateArpMode;
|
||||
}
|
||||
|
||||
log.info("Modified");
|
||||
}
|
||||
|
||||
private String getArpMode() {
|
||||
Set<ConfigProperty> properties = configService.getProperties(this.getClass().getName());
|
||||
return getPropertyValue(properties, ARP_MODE);
|
||||
}
|
||||
|
||||
private void processArpPacket(PacketContext context, Ethernet ethernet) {
|
||||
ARP arp = (ARP) ethernet.getPayload();
|
||||
|
||||
if (arp.getOpCode() == ARP.OP_REQUEST && arpMode.equals(ARP_PROXY_MODE)) {
|
||||
if (arp.getOpCode() == ARP.OP_REQUEST && ARP_PROXY_MODE.equals(getArpMode())) {
|
||||
if (log.isTraceEnabled()) {
|
||||
log.trace("ARP request received from {} for {}",
|
||||
Ip4Address.valueOf(arp.getSenderProtocolAddress()).toString(),
|
||||
@ -381,7 +377,7 @@ public class OpenstackRoutingArpHandler {
|
||||
* @param install flow rule installation flag
|
||||
*/
|
||||
private void setFloatingIpArpRuleForGateway(OpenstackNode gateway, boolean install) {
|
||||
if (arpMode.equals(ARP_BROADCAST_MODE)) {
|
||||
if (ARP_BROADCAST_MODE.equals(getArpMode())) {
|
||||
|
||||
Set<OpenstackNode> completedGws = osNodeService.completeNodes(GATEWAY);
|
||||
Set<OpenstackNode> finalGws = Sets.newConcurrentHashSet();
|
||||
@ -442,7 +438,7 @@ public class OpenstackRoutingArpHandler {
|
||||
InstancePort port,
|
||||
Set<OpenstackNode> gateways,
|
||||
boolean install) {
|
||||
if (arpMode.equals(ARP_BROADCAST_MODE)) {
|
||||
if (ARP_BROADCAST_MODE.equals(getArpMode())) {
|
||||
|
||||
OpenstackNode gw = getGwByInstancePort(gateways, port);
|
||||
|
||||
@ -469,7 +465,7 @@ public class OpenstackRoutingArpHandler {
|
||||
private synchronized void setFloatingIpArpRule(NetFloatingIP fip,
|
||||
Set<OpenstackNode> gateways,
|
||||
boolean install) {
|
||||
if (arpMode.equals(ARP_BROADCAST_MODE)) {
|
||||
if (ARP_BROADCAST_MODE.equals(getArpMode())) {
|
||||
|
||||
if (fip == null) {
|
||||
log.warn("Failed to set ARP broadcast rule for floating IP");
|
||||
@ -671,7 +667,7 @@ public class OpenstackRoutingArpHandler {
|
||||
}
|
||||
|
||||
private void setFakeGatewayArpRule(ExternalGateway extGw, boolean install) {
|
||||
if (arpMode.equals(ARP_BROADCAST_MODE)) {
|
||||
if (ARP_BROADCAST_MODE.equals(getArpMode())) {
|
||||
|
||||
if (extGw == null) {
|
||||
return;
|
||||
@ -859,7 +855,7 @@ public class OpenstackRoutingArpHandler {
|
||||
}
|
||||
|
||||
private void setDefaultArpRule(OpenstackNode osNode, boolean install) {
|
||||
switch (arpMode) {
|
||||
switch (getArpMode()) {
|
||||
case ARP_PROXY_MODE:
|
||||
setDefaultArpRuleForProxyMode(osNode, install);
|
||||
break;
|
||||
@ -868,7 +864,7 @@ public class OpenstackRoutingArpHandler {
|
||||
break;
|
||||
default:
|
||||
log.warn("Invalid ARP mode {}. Please use either " +
|
||||
"broadcast or proxy mode.", arpMode);
|
||||
"broadcast or proxy mode.", getArpMode());
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@ -32,6 +32,7 @@ import org.onlab.packet.IpAddress;
|
||||
import org.onlab.packet.MacAddress;
|
||||
import org.onlab.util.Tools;
|
||||
import org.onosproject.cfg.ComponentConfigService;
|
||||
import org.onosproject.cfg.ConfigProperty;
|
||||
import org.onosproject.cluster.ClusterService;
|
||||
import org.onosproject.cluster.LeadershipService;
|
||||
import org.onosproject.cluster.NodeId;
|
||||
@ -84,6 +85,7 @@ import static org.onosproject.openstacknetworking.api.Constants.PRIORITY_ARP_GAT
|
||||
import static org.onosproject.openstacknetworking.api.Constants.PRIORITY_ARP_REPLY_RULE;
|
||||
import static org.onosproject.openstacknetworking.api.Constants.PRIORITY_ARP_REQUEST_RULE;
|
||||
import static org.onosproject.openstacknetworking.api.Constants.PRIORITY_ARP_SUBNET_RULE;
|
||||
import static org.onosproject.openstacknetworking.util.OpenstackNetworkingUtil.getPropertyValue;
|
||||
import static org.onosproject.openstacknetworking.util.RulePopulatorUtil.buildExtension;
|
||||
import static org.onosproject.openstacknode.api.OpenstackNode.NodeType.COMPUTE;
|
||||
|
||||
@ -189,24 +191,16 @@ public final class OpenstackSwitchingArpHandler {
|
||||
|
||||
@Modified
|
||||
void modified(ComponentContext context) {
|
||||
Dictionary<?, ?> properties = context.getProperties();
|
||||
String updatedMac;
|
||||
|
||||
updatedMac = Tools.get(properties, GATEWAY_MAC);
|
||||
if (!Strings.isNullOrEmpty(updatedMac) && !updatedMac.equals(gatewayMac)) {
|
||||
gatewayMac = updatedMac;
|
||||
}
|
||||
|
||||
String updateArpMode;
|
||||
|
||||
updateArpMode = Tools.get(properties, ARP_MODE);
|
||||
if (!Strings.isNullOrEmpty(updateArpMode) && !updateArpMode.equals(arpMode)) {
|
||||
arpMode = updateArpMode;
|
||||
}
|
||||
readComponentConfiguration(context);
|
||||
|
||||
log.info("Modified");
|
||||
}
|
||||
|
||||
private String getArpMode() {
|
||||
Set<ConfigProperty> properties = configService.getProperties(this.getClass().getName());
|
||||
return getPropertyValue(properties, ARP_MODE);
|
||||
}
|
||||
|
||||
private void addSubnetGateway(Subnet osSubnet) {
|
||||
if (Strings.isNullOrEmpty(osSubnet.getGateway())) {
|
||||
return;
|
||||
@ -236,7 +230,7 @@ public final class OpenstackSwitchingArpHandler {
|
||||
private void processPacketIn(PacketContext context, Ethernet ethPacket) {
|
||||
|
||||
// if the ARP mode is configured as broadcast mode, we simply ignore ARP packet_in
|
||||
if (arpMode.equals(ARP_BROADCAST_MODE)) {
|
||||
if (ARP_BROADCAST_MODE.equals(getArpMode())) {
|
||||
return;
|
||||
}
|
||||
|
||||
@ -304,7 +298,7 @@ public final class OpenstackSwitchingArpHandler {
|
||||
*/
|
||||
private void setFakeGatewayArpRule(Subnet osSubnet, boolean install, OpenstackNode osNode) {
|
||||
|
||||
if (arpMode.equals(ARP_BROADCAST_MODE)) {
|
||||
if (ARP_BROADCAST_MODE.equals(getArpMode())) {
|
||||
String gateway = osSubnet.getGateway();
|
||||
|
||||
TrafficSelector selector = DefaultTrafficSelector.builder()
|
||||
@ -347,221 +341,6 @@ public final class OpenstackSwitchingArpHandler {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* An internal packet processor which processes ARP request, and results in
|
||||
* packet-out ARP reply.
|
||||
*/
|
||||
private class InternalPacketProcessor implements PacketProcessor {
|
||||
|
||||
@Override
|
||||
public void process(PacketContext context) {
|
||||
if (context.isHandled()) {
|
||||
return;
|
||||
}
|
||||
|
||||
Ethernet ethPacket = context.inPacket().parsed();
|
||||
if (ethPacket == null || ethPacket.getEtherType() != Ethernet.TYPE_ARP) {
|
||||
return;
|
||||
}
|
||||
processPacketIn(context, ethPacket);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* An internal network listener which listens to openstack network event,
|
||||
* manages the gateway collection and installs flow rule that handles
|
||||
* ARP request in data plane.
|
||||
*/
|
||||
private class InternalOpenstackNetworkListener implements OpenstackNetworkListener {
|
||||
|
||||
@Override
|
||||
public boolean isRelevant(OpenstackNetworkEvent event) {
|
||||
Subnet osSubnet = event.subnet();
|
||||
if (osSubnet == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Network network = osNetworkService.network(osSubnet.getNetworkId());
|
||||
|
||||
if (network == null) {
|
||||
log.warn("Network is not specified.");
|
||||
return false;
|
||||
} else {
|
||||
if (network.getNetworkType().equals(NetworkType.FLAT)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// do not allow to proceed without leadership
|
||||
NodeId leader = leadershipService.getLeader(appId.name());
|
||||
if (!Objects.equals(localNodeId, leader)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return !Strings.isNullOrEmpty(osSubnet.getGateway());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void event(OpenstackNetworkEvent event) {
|
||||
switch (event.type()) {
|
||||
case OPENSTACK_SUBNET_CREATED:
|
||||
case OPENSTACK_SUBNET_UPDATED:
|
||||
addSubnetGateway(event.subnet());
|
||||
setFakeGatewayArpRule(event.subnet(), true, null);
|
||||
break;
|
||||
case OPENSTACK_SUBNET_REMOVED:
|
||||
removeSubnetGateway(event.subnet());
|
||||
setFakeGatewayArpRule(event.subnet(), false, null);
|
||||
break;
|
||||
case OPENSTACK_NETWORK_CREATED:
|
||||
case OPENSTACK_NETWORK_UPDATED:
|
||||
case OPENSTACK_NETWORK_REMOVED:
|
||||
case OPENSTACK_PORT_CREATED:
|
||||
case OPENSTACK_PORT_UPDATED:
|
||||
case OPENSTACK_PORT_REMOVED:
|
||||
default:
|
||||
// do nothing for the other events
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* An internal openstack node listener which is used for listening openstack
|
||||
* node activity. As long as a node is in complete state, we will install
|
||||
* default ARP rule to handle ARP request.
|
||||
*/
|
||||
private class InternalNodeEventListener implements OpenstackNodeListener {
|
||||
|
||||
@Override
|
||||
public boolean isRelevant(OpenstackNodeEvent event) {
|
||||
// do not allow to proceed without leadership
|
||||
NodeId leader = leadershipService.getLeader(appId.name());
|
||||
return Objects.equals(localNodeId, leader) && event.subject().type() == COMPUTE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void event(OpenstackNodeEvent event) {
|
||||
OpenstackNode osNode = event.subject();
|
||||
switch (event.type()) {
|
||||
case OPENSTACK_NODE_COMPLETE:
|
||||
setDefaultArpRule(osNode, true);
|
||||
break;
|
||||
case OPENSTACK_NODE_INCOMPLETE:
|
||||
setDefaultArpRule(osNode, false);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private void setDefaultArpRule(OpenstackNode osNode, boolean install) {
|
||||
switch (arpMode) {
|
||||
case ARP_PROXY_MODE:
|
||||
setDefaultArpRuleForProxyMode(osNode, install);
|
||||
break;
|
||||
case ARP_BROADCAST_MODE:
|
||||
setDefaultArpRuleForBroadcastMode(osNode, install);
|
||||
|
||||
// we do not add fake gateway ARP rules for FLAT network
|
||||
// ARP packets generated by FLAT typed VM should not be
|
||||
// delegated to switch to handle
|
||||
osNetworkService.subnets().stream().filter(subnet ->
|
||||
osNetworkService.network(subnet.getNetworkId()) != null &&
|
||||
osNetworkService.network(subnet.getNetworkId())
|
||||
.getNetworkType() == NetworkType.FLAT)
|
||||
.forEach(subnet ->
|
||||
setFakeGatewayArpRule(subnet, install, osNode));
|
||||
break;
|
||||
default:
|
||||
log.warn("Invalid ARP mode {}. Please use either " +
|
||||
"broadcast or proxy mode.", arpMode);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private void setDefaultArpRuleForProxyMode(OpenstackNode osNode, boolean install) {
|
||||
TrafficSelector selector = DefaultTrafficSelector.builder()
|
||||
.matchEthType(EthType.EtherType.ARP.ethType().toShort())
|
||||
.build();
|
||||
|
||||
TrafficTreatment treatment = DefaultTrafficTreatment.builder()
|
||||
.punt()
|
||||
.build();
|
||||
|
||||
osFlowRuleService.setRule(
|
||||
appId,
|
||||
osNode.intgBridge(),
|
||||
selector,
|
||||
treatment,
|
||||
PRIORITY_ARP_CONTROL_RULE,
|
||||
DHCP_ARP_TABLE,
|
||||
install
|
||||
);
|
||||
}
|
||||
|
||||
private void setDefaultArpRuleForBroadcastMode(OpenstackNode osNode, boolean install) {
|
||||
TrafficSelector selector = DefaultTrafficSelector.builder()
|
||||
.matchEthType(EthType.EtherType.ARP.ethType().toShort())
|
||||
.matchArpOp(ARP.OP_REQUEST)
|
||||
.build();
|
||||
|
||||
TrafficTreatment treatment = DefaultTrafficTreatment.builder()
|
||||
.setOutput(PortNumber.FLOOD)
|
||||
.build();
|
||||
|
||||
osFlowRuleService.setRule(
|
||||
appId,
|
||||
osNode.intgBridge(),
|
||||
selector,
|
||||
treatment,
|
||||
PRIORITY_ARP_SUBNET_RULE,
|
||||
DHCP_ARP_TABLE,
|
||||
install
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* An internal instance port listener which listens the port events generated
|
||||
* from VM. When ARP a host which located in a remote compute node, we specify
|
||||
* both ARP OP mode as REQUEST and Target Protocol Address (TPA) with
|
||||
* host IP address. When ARP a host which located in a local compute node,
|
||||
* we specify only ARP OP mode as REQUEST.
|
||||
*/
|
||||
private class InternalInstancePortListener implements InstancePortListener {
|
||||
|
||||
@Override
|
||||
public boolean isRelevant(InstancePortEvent event) {
|
||||
|
||||
if (arpMode.equals(ARP_PROXY_MODE)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
InstancePort instPort = event.subject();
|
||||
return mastershipService.isLocalMaster(instPort.deviceId());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void event(InstancePortEvent event) {
|
||||
switch (event.type()) {
|
||||
case OPENSTACK_INSTANCE_PORT_UPDATED:
|
||||
case OPENSTACK_INSTANCE_PORT_DETECTED:
|
||||
setArpRequestRule(event.subject(), true);
|
||||
setArpReplyRule(event.subject(), true);
|
||||
break;
|
||||
case OPENSTACK_INSTANCE_PORT_VANISHED:
|
||||
setArpRequestRule(event.subject(), false);
|
||||
setArpReplyRule(event.subject(), false);
|
||||
break;
|
||||
case OPENSTACK_INSTANCE_MIGRATION_ENDED:
|
||||
setArpRequestRule(event.subject(), false);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Installs flow rules to match ARP request packets.
|
||||
*
|
||||
@ -726,5 +505,244 @@ public final class OpenstackSwitchingArpHandler {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Extracts properties from the component configuration context.
|
||||
*
|
||||
* @param context the component context
|
||||
*/
|
||||
private void readComponentConfiguration(ComponentContext context) {
|
||||
Dictionary<?, ?> properties = context.getProperties();
|
||||
|
||||
String updatedMac = Tools.get(properties, GATEWAY_MAC);
|
||||
gatewayMac = updatedMac != null ? updatedMac : DEFAULT_GATEWAY_MAC_STR;
|
||||
log.info("Configured. Gateway MAC is {}", gatewayMac);
|
||||
}
|
||||
|
||||
/**
|
||||
* An internal packet processor which processes ARP request, and results in
|
||||
* packet-out ARP reply.
|
||||
*/
|
||||
private class InternalPacketProcessor implements PacketProcessor {
|
||||
|
||||
@Override
|
||||
public void process(PacketContext context) {
|
||||
if (context.isHandled()) {
|
||||
return;
|
||||
}
|
||||
|
||||
Ethernet ethPacket = context.inPacket().parsed();
|
||||
if (ethPacket == null || ethPacket.getEtherType() != Ethernet.TYPE_ARP) {
|
||||
return;
|
||||
}
|
||||
processPacketIn(context, ethPacket);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* An internal network listener which listens to openstack network event,
|
||||
* manages the gateway collection and installs flow rule that handles
|
||||
* ARP request in data plane.
|
||||
*/
|
||||
private class InternalOpenstackNetworkListener implements OpenstackNetworkListener {
|
||||
|
||||
@Override
|
||||
public boolean isRelevant(OpenstackNetworkEvent event) {
|
||||
Subnet osSubnet = event.subnet();
|
||||
if (osSubnet == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Network network = osNetworkService.network(osSubnet.getNetworkId());
|
||||
|
||||
if (network == null) {
|
||||
log.warn("Network is not specified.");
|
||||
return false;
|
||||
} else {
|
||||
if (network.getNetworkType().equals(NetworkType.FLAT)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// do not allow to proceed without leadership
|
||||
NodeId leader = leadershipService.getLeader(appId.name());
|
||||
if (!Objects.equals(localNodeId, leader)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return !Strings.isNullOrEmpty(osSubnet.getGateway());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void event(OpenstackNetworkEvent event) {
|
||||
switch (event.type()) {
|
||||
case OPENSTACK_SUBNET_CREATED:
|
||||
case OPENSTACK_SUBNET_UPDATED:
|
||||
addSubnetGateway(event.subnet());
|
||||
setFakeGatewayArpRule(event.subnet(), true, null);
|
||||
break;
|
||||
case OPENSTACK_SUBNET_REMOVED:
|
||||
removeSubnetGateway(event.subnet());
|
||||
setFakeGatewayArpRule(event.subnet(), false, null);
|
||||
break;
|
||||
case OPENSTACK_NETWORK_CREATED:
|
||||
case OPENSTACK_NETWORK_UPDATED:
|
||||
case OPENSTACK_NETWORK_REMOVED:
|
||||
case OPENSTACK_PORT_CREATED:
|
||||
case OPENSTACK_PORT_UPDATED:
|
||||
case OPENSTACK_PORT_REMOVED:
|
||||
default:
|
||||
// do nothing for the other events
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* An internal openstack node listener which is used for listening openstack
|
||||
* node activity. As long as a node is in complete state, we will install
|
||||
* default ARP rule to handle ARP request.
|
||||
*/
|
||||
private class InternalNodeEventListener implements OpenstackNodeListener {
|
||||
|
||||
@Override
|
||||
public boolean isRelevant(OpenstackNodeEvent event) {
|
||||
// do not allow to proceed without leadership
|
||||
NodeId leader = leadershipService.getLeader(appId.name());
|
||||
return Objects.equals(localNodeId, leader) && event.subject().type() == COMPUTE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void event(OpenstackNodeEvent event) {
|
||||
OpenstackNode osNode = event.subject();
|
||||
switch (event.type()) {
|
||||
case OPENSTACK_NODE_COMPLETE:
|
||||
setDefaultArpRule(osNode, true);
|
||||
setAllArpRules(true);
|
||||
break;
|
||||
case OPENSTACK_NODE_INCOMPLETE:
|
||||
setDefaultArpRule(osNode, false);
|
||||
setAllArpRules(false);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private void setDefaultArpRule(OpenstackNode osNode, boolean install) {
|
||||
switch (getArpMode()) {
|
||||
case ARP_PROXY_MODE:
|
||||
setDefaultArpRuleForProxyMode(osNode, install);
|
||||
break;
|
||||
case ARP_BROADCAST_MODE:
|
||||
setDefaultArpRuleForBroadcastMode(osNode, install);
|
||||
|
||||
// we do not add fake gateway ARP rules for FLAT network
|
||||
// ARP packets generated by FLAT typed VM should not be
|
||||
// delegated to switch to handle
|
||||
osNetworkService.subnets().stream().filter(subnet ->
|
||||
osNetworkService.network(subnet.getNetworkId()) != null &&
|
||||
osNetworkService.network(subnet.getNetworkId())
|
||||
.getNetworkType() != NetworkType.FLAT)
|
||||
.forEach(subnet ->
|
||||
setFakeGatewayArpRule(subnet, install, osNode));
|
||||
break;
|
||||
default:
|
||||
log.warn("Invalid ARP mode {}. Please use either " +
|
||||
"broadcast or proxy mode.", getArpMode());
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private void setDefaultArpRuleForProxyMode(OpenstackNode osNode, boolean install) {
|
||||
TrafficSelector selector = DefaultTrafficSelector.builder()
|
||||
.matchEthType(EthType.EtherType.ARP.ethType().toShort())
|
||||
.build();
|
||||
|
||||
TrafficTreatment treatment = DefaultTrafficTreatment.builder()
|
||||
.punt()
|
||||
.build();
|
||||
|
||||
osFlowRuleService.setRule(
|
||||
appId,
|
||||
osNode.intgBridge(),
|
||||
selector,
|
||||
treatment,
|
||||
PRIORITY_ARP_CONTROL_RULE,
|
||||
DHCP_ARP_TABLE,
|
||||
install
|
||||
);
|
||||
}
|
||||
|
||||
private void setDefaultArpRuleForBroadcastMode(OpenstackNode osNode, boolean install) {
|
||||
TrafficSelector selector = DefaultTrafficSelector.builder()
|
||||
.matchEthType(EthType.EtherType.ARP.ethType().toShort())
|
||||
.matchArpOp(ARP.OP_REQUEST)
|
||||
.build();
|
||||
|
||||
TrafficTreatment treatment = DefaultTrafficTreatment.builder()
|
||||
.setOutput(PortNumber.FLOOD)
|
||||
.build();
|
||||
|
||||
osFlowRuleService.setRule(
|
||||
appId,
|
||||
osNode.intgBridge(),
|
||||
selector,
|
||||
treatment,
|
||||
PRIORITY_ARP_SUBNET_RULE,
|
||||
DHCP_ARP_TABLE,
|
||||
install
|
||||
);
|
||||
}
|
||||
|
||||
private void setAllArpRules(boolean install) {
|
||||
if (ARP_BROADCAST_MODE.equals(getArpMode())) {
|
||||
instancePortService.instancePorts().forEach(p -> {
|
||||
setArpRequestRule(p, install);
|
||||
setArpReplyRule(p, install);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* An internal instance port listener which listens the port events generated
|
||||
* from VM. When ARP a host which located in a remote compute node, we specify
|
||||
* both ARP OP mode as REQUEST and Target Protocol Address (TPA) with
|
||||
* host IP address. When ARP a host which located in a local compute node,
|
||||
* we specify only ARP OP mode as REQUEST.
|
||||
*/
|
||||
private class InternalInstancePortListener implements InstancePortListener {
|
||||
|
||||
@Override
|
||||
public boolean isRelevant(InstancePortEvent event) {
|
||||
|
||||
if (ARP_PROXY_MODE.equals(getArpMode())) {
|
||||
return false;
|
||||
}
|
||||
|
||||
InstancePort instPort = event.subject();
|
||||
return mastershipService.isLocalMaster(instPort.deviceId());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void event(InstancePortEvent event) {
|
||||
switch (event.type()) {
|
||||
case OPENSTACK_INSTANCE_PORT_UPDATED:
|
||||
case OPENSTACK_INSTANCE_PORT_DETECTED:
|
||||
setArpRequestRule(event.subject(), true);
|
||||
setArpReplyRule(event.subject(), true);
|
||||
break;
|
||||
case OPENSTACK_INSTANCE_PORT_VANISHED:
|
||||
setArpRequestRule(event.subject(), false);
|
||||
setArpReplyRule(event.subject(), false);
|
||||
break;
|
||||
case OPENSTACK_INSTANCE_MIGRATION_ENDED:
|
||||
setArpRequestRule(event.subject(), false);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -19,10 +19,11 @@ import com.fasterxml.jackson.databind.JsonNode;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.fasterxml.jackson.databind.node.ObjectNode;
|
||||
import com.google.common.base.Strings;
|
||||
import org.onosproject.cfg.ConfigProperty;
|
||||
import org.onosproject.net.DeviceId;
|
||||
import org.onosproject.openstacknetworking.api.InstancePort;
|
||||
import org.onosproject.openstacknetworking.api.OpenstackRouterAdminService;
|
||||
import org.onosproject.openstacknetworking.api.OpenstackNetworkService;
|
||||
import org.onosproject.openstacknetworking.api.OpenstackRouterAdminService;
|
||||
import org.onosproject.openstacknode.api.OpenstackAuth;
|
||||
import org.onosproject.openstacknode.api.OpenstackAuth.Perspective;
|
||||
import org.onosproject.openstacknode.api.OpenstackNode;
|
||||
@ -54,6 +55,7 @@ import java.security.cert.X509Certificate;
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
import java.util.TreeMap;
|
||||
|
||||
@ -348,6 +350,19 @@ public final class OpenstackNetworkingUtil {
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Obtains the property value with specified property key name.
|
||||
*
|
||||
* @param properties a collection of properties
|
||||
* @param name key name
|
||||
* @return mapping value
|
||||
*/
|
||||
public static String getPropertyValue(Set<ConfigProperty> properties, String name) {
|
||||
Optional<ConfigProperty> property =
|
||||
properties.stream().filter(p -> p.name().equals(name)).findFirst();
|
||||
return property.map(ConfigProperty::value).orElse(null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds up and a complete endpoint URL from gateway node.
|
||||
*
|
||||
|
||||
@ -68,9 +68,16 @@
|
||||
<ref component-id="ipAddressCompleter"/>
|
||||
</completers>
|
||||
</command>
|
||||
<command>
|
||||
<action class="org.onosproject.openstacknetworking.cli.OpenstackConfigArpModeCommand" />
|
||||
<completers>
|
||||
<ref component-id="arpModeCompleter"/>
|
||||
</completers>
|
||||
</command>
|
||||
</command-bundle>
|
||||
|
||||
<bean id="ipAddressCompleter" class="org.onosproject.openstacknetworking.cli.IpAddressCompleter"/>
|
||||
<bean id="macAddressCompleter" class="org.onosproject.openstacknetworking.cli.MacAddressCompleter"/>
|
||||
<bean id="vlanIdCompleter" class="org.onosproject.openstacknetworking.cli.VlanIdCompleter"/>
|
||||
<bean id="arpModeCompleter" class="org.onosproject.openstacknetworking.cli.ArpModeCompleter"/>
|
||||
</blueprint>
|
||||
|
||||
@ -45,7 +45,6 @@ import static org.junit.Assert.assertArrayEquals;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.fail;
|
||||
import static org.onosproject.net.NetTestTools.connectPoint;
|
||||
import static org.onosproject.openstacknetworking.api.Constants.ARP_PROXY_MODE;
|
||||
|
||||
public class OpenstackSwitchingArpHandlerTest {
|
||||
|
||||
@ -68,7 +67,6 @@ public class OpenstackSwitchingArpHandlerTest {
|
||||
arpHandler.osNetworkService = new TestOpenstackNetworkService();
|
||||
arpHandler.osNodeService = new TestOpenstackNodeService();
|
||||
arpHandler.osFlowRuleService = new TestOpenstackFlowRuleService();
|
||||
arpHandler.arpMode = ARP_PROXY_MODE;
|
||||
arpHandler.clusterService = new TestClusterService();
|
||||
arpHandler.leadershipService = new TestLeadershipService();
|
||||
arpHandler.activate();
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user