Daniel Park
Committed by Gerrit Code Review

[ONOS-3946] Implement IcmpHandler for OpenstackRoutingService

- Process Icmp packet sent from Host to external network for OpenstackGateway Node
- Process Arp packet sent from physical  router to gateway

Change-Id: Ifcde71a9ca10180682811c9e1bcf58f991b36443
......@@ -68,7 +68,6 @@ public class OpenstackRouterCodec extends JsonCodec<OpenstackRouter> {
String tenantId = checkNotNull(routerInfo.path(TENANT_ID).asText());
String id = checkNotNull(routerInfo.path(ID).asText());
String name = checkNotNull(routerInfo.path(NAME).asText());
String status = checkNotNull(routerInfo.path(STATUS).asText());
String adminStateUp = checkNotNull(routerInfo.path(ADMIN_STATE_UP).asText());
OpenstackExternalGateway.Builder osExtBuiler = new OpenstackExternalGateway.Builder();
......@@ -98,7 +97,7 @@ public class OpenstackRouterCodec extends JsonCodec<OpenstackRouter> {
.tenantId(tenantId)
.id(id)
.name(name)
.status(OpenstackRouter.RouterStatus.valueOf(status))
.status(OpenstackRouter.RouterStatus.ACTIVE)
.adminStateUp(Boolean.valueOf(adminStateUp))
.gatewayExternalInfo(osExtBuiler.build());
......
......@@ -27,12 +27,13 @@ import static com.google.common.base.Preconditions.checkNotNull;
/**
* Contains OpenstackPort Information.
*/
public class OpenstackPortInfo {
public final class OpenstackPortInfo {
private final Ip4Address hostIp;
private final MacAddress hostMac;
private final DeviceId deviceId;
private final long vni;
private final Ip4Address gatewayIP;
private final String networkId;
private final Collection<String> securityGroups;
/**
......@@ -46,12 +47,13 @@ public class OpenstackPortInfo {
* @param securityGroups security group list
*/
public OpenstackPortInfo(Ip4Address hostIp, MacAddress hostMac, DeviceId deviceId, long vni,
Ip4Address gatewayIP, Collection<String> securityGroups) {
Ip4Address gatewayIP, String networkId, Collection<String> securityGroups) {
this.hostIp = hostIp;
this.hostMac = hostMac;
this.deviceId = deviceId;
this.vni = vni;
this.gatewayIP = gatewayIP;
this.networkId = networkId;
this.securityGroups = securityGroups;
}
......@@ -101,6 +103,15 @@ public class OpenstackPortInfo {
}
/**
* Returns network ID.
*
* @return network ID
*/
public String networkId() {
return networkId;
}
/**
* Returns Security Group ID list.
*
* @return list of Security Group ID
......@@ -129,11 +140,12 @@ public class OpenstackPortInfo {
private long vni;
private Ip4Address gatewayIP;
private Collection<String> securityGroups;
private String networkId;
/**
* Sets the IP address of the port.
*
* @param gatewayIP
* @param gatewayIP gateway IP
* @return Builder reference
*/
public Builder setGatewayIP(Ip4Address gatewayIP) {
......@@ -142,6 +154,17 @@ public class OpenstackPortInfo {
}
/**
* Sets the network ID.
*
* @param networkId network id
* @return Builder reference
*/
public Builder setNetworkId(String networkId) {
this.networkId = checkNotNull(networkId, "networkId cannot be null");
return this;
}
/**
* Sets the host IP address of the port.
*
* @param hostIp host IP address
......@@ -202,16 +225,7 @@ public class OpenstackPortInfo {
* @return OpenstackPortInfo reference
*/
public OpenstackPortInfo build() {
return new OpenstackPortInfo(this);
return new OpenstackPortInfo(hostIp, hostMac, deviceId, vni, gatewayIP, networkId, securityGroups);
}
}
private OpenstackPortInfo(Builder builder) {
hostIp = builder.hostIp;
hostMac = builder.hostMac;
deviceId = builder.deviceId;
vni = builder.vni;
gatewayIP = builder.gatewayIP;
securityGroups = builder.securityGroups;
}
}
......
{
"apps" : {
"org.onosproject.openstackswitching" : {
"openstackswitching" : {
"do_not_push_flows" : "false",
"neutron_server" : "http://192.168.56.103:9696/v2.0/",
"keystone_server" : "http://192.168.56.103:5000/v2.0/",
"user_name" : "admin",
"password" : "nova",
"physicalRouterMac" : "00:00:00:00:00:20",
"org.onosproject.openstackrouting" : {
"openstackrouting" : {
"physicalRouterMac" : "2a:a1:8a:89:dd:a4",
"gatewayBridgeId" : "of:0000000000000003",
"gatewayExternalInterfaceName" : "veth0",
"gatewayExternalInterfaceMac" : "be:15:c6:b0:df:9f"
}
},
"org.onosproject.openstacknode" : {
"openstacknode" : {
"nodes" : [
{
"hostname" : "compute-01",
"ovsdbIp" : "192.168.56.102",
"ovsdbPort" : "6640",
"bridgeId" : "of:0000000000000001",
"openstackNodeType" : "COMPUTENODE"
},
{
"hostname" : "compute-02",
"ovsdbIp" : "192.168.56.101",
"ovsdbPort" : "6640",
"bridgeId" : "of:0000000000000002",
"openstackNodeType" : "COMPUTENODE"
},
{
"hostname" : "network",
"ovsdbIp" : "192.168.56.106",
"ovsdbPort" : "6640",
"bridgeId" : "of:0000000000000003",
"openstackNodeType" : "GATEWAYNODE",
"externalIfName" : "eth3",
"externalIfMacAddress" : "00:00:00:00:00:11"
}
{
"hostname" : "compute-01",
"ovsdbIp" : "192.168.56.112",
"ovsdbPort" : "6640",
"bridgeId" : "of:0000000000000001",
"openstackNodeType" : "COMPUTENODE"
},
{
"hostname" : "compute-02",
"ovsdbIp" : "192.168.56.113",
"ovsdbPort" : "6640",
"bridgeId" : "of:0000000000000002",
"openstackNodeType" : "COMPUTENODE"
},
{
"hostname" : "network",
"ovsdbIp" : "192.168.56.114",
"ovsdbPort" : "6640",
"bridgeId" : "of:0000000000000003",
"openstackNodeType" : "GATEWAYNODE",
"gatewayExternalInterfaceName" : "veth0",
"gatewayExternalInterfaceMac" : "be:15:c6:b0:df:9f"
}
]
}
}
}
},
"org.onosproject.openstackinterface" : {
"openstackinterface" : {
"neutron_server" : "http://192.168.56.111:9696/v2.0/",
"keystone_server" : "http://192.168.56.111:5000/v2.0/",
"user_name" : "admin",
"password" : "nova"
}
}
},
"devices" : {
"of:0000000000000001" : {
......@@ -49,3 +59,4 @@
}
}
}
......
/*
* Copyright 2016 Open Networking Laboratory
*
* 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.routing;
import org.onlab.packet.ARP;
import org.onlab.packet.EthType;
import org.onlab.packet.Ethernet;
import org.onlab.packet.IPv4;
import org.onlab.packet.Ip4Address;
import org.onlab.packet.IpAddress;
import org.onlab.packet.MacAddress;
import org.onosproject.core.ApplicationId;
import org.onosproject.net.DeviceId;
import org.onosproject.net.flow.DefaultTrafficSelector;
import org.onosproject.net.flow.DefaultTrafficTreatment;
import org.onosproject.net.flow.TrafficSelector;
import org.onosproject.net.flow.TrafficTreatment;
import org.onosproject.net.packet.DefaultOutboundPacket;
import org.onosproject.net.packet.PacketContext;
import org.onosproject.net.packet.PacketPriority;
import org.onosproject.net.packet.PacketService;
import org.onosproject.openstackinterface.OpenstackInterfaceService;
import org.onosproject.openstackinterface.OpenstackPort;
import org.slf4j.Logger;
import java.nio.ByteBuffer;
import java.util.Optional;
import static com.google.common.base.Preconditions.checkNotNull;
import static org.slf4j.LoggerFactory.getLogger;
/**
* Handle ARP packet sent from Openstack Gateway nodes.
*/
public class OpenstackRoutingArpHandler {
protected final Logger log = getLogger(getClass());
private final PacketService packetService;
private final OpenstackInterfaceService openstackService;
private final OpenstackRoutingConfig config;
private static final String NETWORK_ROUTER_GATEWAY = "network:router_gateway";
/**
* Default constructor.
*
* @param packetService packet service
* @param openstackService openstackInterface service
* @param config openstackRoutingConfig
*/
OpenstackRoutingArpHandler(PacketService packetService, OpenstackInterfaceService openstackService,
OpenstackRoutingConfig config) {
this.packetService = packetService;
this.openstackService = checkNotNull(openstackService);
this.config = checkNotNull(config);
}
/**
* Requests ARP packet to GatewayNode.
*
* @param appId application id
*/
public void requestPacket(ApplicationId appId) {
TrafficSelector arpSelector = DefaultTrafficSelector.builder()
.matchEthType(EthType.EtherType.ARP.ethType().toShort())
.build();
packetService.requestPackets(arpSelector,
PacketPriority.CONTROL,
appId,
Optional.of(DeviceId.deviceId(config.gatewayBridgeId())));
}
/**
* Handles ARP packet.
*
* @param context packet context
* @param ethernet ethernet
*/
public void processArpPacketFromRouter(PacketContext context, Ethernet ethernet) {
checkNotNull(context, "context can not be null");
checkNotNull(ethernet, "ethernet can not be null");
log.info("arpEvent called from {} to {}",
Ip4Address.valueOf(((IPv4) ethernet.getPayload()).getSourceAddress()).toString(),
Ip4Address.valueOf(((IPv4) ethernet.getPayload()).getDestinationAddress()).toString());
ARP arp = (ARP) ethernet.getPayload();
if (arp.getOpCode() != ARP.OP_REQUEST) {
return;
}
IpAddress targetIp = Ip4Address.valueOf(arp.getTargetProtocolAddress());
MacAddress targetMac = getTargetMacForTargetIp(targetIp.getIp4Address());
if (targetMac == MacAddress.NONE) {
return;
}
Ethernet ethReply = ARP.buildArpReply(targetIp.getIp4Address(),
targetMac, ethernet);
TrafficTreatment treatment = DefaultTrafficTreatment.builder()
.setOutput(context.inPacket().receivedFrom().port())
.build();
packetService.emit(new DefaultOutboundPacket(
context.inPacket().receivedFrom().deviceId(),
treatment,
ByteBuffer.wrap(ethReply.serialize())));
}
private MacAddress getTargetMacForTargetIp(Ip4Address targetIp) {
OpenstackPort port = openstackService.ports().stream()
.filter(p -> p.deviceOwner().equals(NETWORK_ROUTER_GATEWAY))
.filter(p -> p.fixedIps().containsValue(targetIp.getIp4Address()))
.findAny().orElse(null);
if (port == null) {
return MacAddress.NONE;
}
return port.macAddress();
}
}
/*
* Copyright 2016 Open Networking Laboratory
*
* 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.routing;
import org.onosproject.core.ApplicationId;
import org.onosproject.net.config.Config;
import org.slf4j.Logger;
import static org.slf4j.LoggerFactory.getLogger;
/**
* Configuration object for OpenstackRouting service.
*/
public class OpenstackRoutingConfig extends Config<ApplicationId> {
protected final Logger log = getLogger(getClass());
public static final String PHYSICAL_ROUTER_MAC = "physicalRouterMac";
public static final String GATEWAY_BRIDGE_ID = "gatewayBridgeId";
public static final String GATEWAY_EXTERNAL_INTERFACE_NAME = "gatewayExternalInterfaceName";
public static final String GATEWAY_EXTERNAL_INTERFACE_MAC = "gatewayExternalInterfaceMac";
/**
* Returns physical router mac.
*
* @return physical router mac
*/
public String physicalRouterMac() {
return this.get("physicalRouterMac", "");
}
/**
* Returns gateway's bridge id.
*
* @return bridge id
*/
public String gatewayBridgeId() {
return this.get("gatewayBridgeId", "");
}
/**
* Returns gateway's external interface name.
*
* @return external interface name
*/
public String gatewayExternalInterfaceName() {
return this.get("gatewayExternalInterfaceName", "");
}
/**
* Returns gateway's external interface mac.
*
* @return external interface mac
*/
public String gatewayExternalInterfaceMac() {
return this.get("gatewayExternalInterfaceMac", "");
}
}
......@@ -71,6 +71,7 @@ public class OpenstackRoutingRulePopulator {
private final OpenstackInterfaceService openstackService;
private final DeviceService deviceService;
private final DriverService driverService;
private final OpenstackRoutingConfig config;
private static final String PORTNAME_PREFIX_VM = "tap";
private static final String PORTNAME_PREFIX_ROUTER = "qr";
......@@ -93,9 +94,6 @@ public class OpenstackRoutingRulePopulator {
private OpenstackRouter router;
private OpenstackRouterInterface routerInterface;
// TODO: This will be replaced to get the information from openstackswitchingservice.
private static final String EXTERNAL_INTERFACE_NAME = "veth0";
/**
* The constructor of openstackRoutingRulePopulator.
*
......@@ -104,20 +102,23 @@ public class OpenstackRoutingRulePopulator {
* @param flowObjectiveService FlowObjectiveService
* @param deviceService DeviceService
* @param driverService DriverService
* @param config OpenstackRoutingConfig
*/
public OpenstackRoutingRulePopulator(ApplicationId appId, OpenstackInterfaceService openstackService,
FlowObjectiveService flowObjectiveService,
DeviceService deviceService, DriverService driverService) {
FlowObjectiveService flowObjectiveService, DeviceService deviceService,
DriverService driverService, OpenstackRoutingConfig config) {
this.appId = appId;
this.flowObjectiveService = flowObjectiveService;
this.openstackService = openstackService;
this.openstackService = checkNotNull(openstackService);
this.deviceService = deviceService;
this.driverService = driverService;
this.config = config;
}
/**
* Populates flow rules for Pnat configurations.
* @param inboundPacket Packet-in event packet
*
* @param inboundPacket Packet-in event packet
* @param openstackPort Target VM information
* @param portNum Pnat port number
* @param externalIp external ip address
......@@ -168,6 +169,7 @@ public class OpenstackRoutingRulePopulator {
tBuilder.setUdpSrc(TpPort.tpPort(portNum));
break;
default:
log.debug("Unsupported IPv4 protocol {}");
break;
}
......@@ -188,7 +190,7 @@ public class OpenstackRoutingRulePopulator {
private Port getPortNumOfExternalInterface() {
return deviceService.getPorts(inboundPacket.receivedFrom().deviceId()).stream()
.filter(p -> p.annotations().value(PORTNAME).equals(EXTERNAL_INTERFACE_NAME))
.filter(p -> p.annotations().value(PORTNAME).equals(config.gatewayExternalInterfaceName()))
.findAny().orElse(null);
}
......@@ -239,7 +241,15 @@ public class OpenstackRoutingRulePopulator {
flowObjectiveService.forward(inboundPacket.receivedFrom().deviceId(), fo);
}
private ExtensionTreatment buildNiciraExtenstion(DeviceId id, Ip4Address hostIp) {
/**
* Returns NiciraExtension treatment.
*
* @param id device id
* @param hostIp host ip
* @return NiciraExtension treatment
*/
public ExtensionTreatment buildNiciraExtenstion(DeviceId id, Ip4Address hostIp) {
Driver driver = driverService.getDriver(id);
DriverHandler driverHandler = new DefaultDriverHandler(new DefaultDriverData(driver, id));
ExtensionTreatmentResolver resolver = driverHandler.behaviour(ExtensionTreatmentResolver.class);
......@@ -257,7 +267,13 @@ public class OpenstackRoutingRulePopulator {
return extensionInstruction;
}
private PortNumber getTunnelPort(DeviceId deviceId) {
/**
* Returns port number of vxlan tunnel.
*
* @param deviceId device id
* @return port number of vxlan tunnel
*/
public PortNumber getTunnelPort(DeviceId deviceId) {
Port port = deviceService.getPorts(deviceId).stream()
.filter(p -> p.annotations().value(PORTNAME).equals(PORTNAME_PREFIX_TUNNEL))
.findAny().orElse(null);
......@@ -343,16 +359,11 @@ public class OpenstackRoutingRulePopulator {
}
private Device getGatewayNode() {
return checkNotNull(StreamSupport.stream(deviceService.getAvailableDevices().spliterator(), false)
.filter(d -> checkGatewayNode(d.id()))
.findAny()
.orElse(null));
return checkNotNull(deviceService.getDevice(DeviceId.deviceId(config.gatewayBridgeId())));
}
private boolean checkGatewayNode(DeviceId deviceId) {
return !deviceService.getPorts(deviceId).stream().anyMatch(port ->
port.annotations().value(PORTNAME).startsWith(PORTNAME_PREFIX_ROUTER) ||
port.annotations().value(PORTNAME).startsWith(PORTNAME_PREFIX_VM));
return deviceId.toString().equals(config.gatewayBridgeId());
}
private long getVni(OpenstackPort openstackPort) {
......
......@@ -94,6 +94,7 @@ public class OpenstackSwitchingManager implements OpenstackSwitchingService {
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
protected DriverService driverService;
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
protected OpenstackInterfaceService openstackService;
public static final String PORTNAME_PREFIX_VM = "tap";
......@@ -126,6 +127,7 @@ public class OpenstackSwitchingManager implements OpenstackSwitchingService {
packetService.addProcessor(internalPacketProcessor, PacketProcessor.director(1));
deviceService.addListener(internalDeviceListener);
hostService.addListener(internalHostListener);
arpHandler = new OpenstackArpHandler(openstackService, packetService, hostService);
arpHandler = new OpenstackArpHandler(openstackService, packetService, hostService);
sgRulePopulator = new OpenstackSecurityGroupRulePopulator(appId, openstackService, flowObjectiveService);
......@@ -204,10 +206,12 @@ public class OpenstackSwitchingManager implements OpenstackSwitchingService {
@Override
public void createNetwork(OpenstackNetwork openstackNetwork) {
//TODO
}
@Override
public void createSubnet(OpenstackSubnet openstackSubnet) {
//TODO
}
@Override
......@@ -296,9 +300,17 @@ public class OpenstackSwitchingManager implements OpenstackSwitchingService {
private void updatePortMap(DeviceId deviceId, String portName, Collection<OpenstackNetwork> networks,
Collection<OpenstackSubnet> subnets, OpenstackPort openstackPort) {
long vni = Long.parseLong(networks.stream()
long vni;
OpenstackNetwork openstackNetwork = networks.stream()
.filter(n -> n.id().equals(openstackPort.networkId()))
.findAny().orElse(null).segmentId());
.findAny().orElse(null);
if (openstackNetwork != null) {
vni = Long.parseLong(openstackNetwork.segmentId());
} else {
log.debug("updatePortMap failed because there's no OpenstackNetwork matches {}", openstackPort.networkId());
return;
}
OpenstackSubnet openstackSubnet = subnets.stream()
.filter(n -> n.networkId().equals(openstackPort.networkId()))
......@@ -312,6 +324,7 @@ public class OpenstackSwitchingManager implements OpenstackSwitchingService {
.setHostMac(openstackPort.macAddress())
.setVni(vni)
.setGatewayIP(gatewayIPAddress)
.setNetworkId(openstackPort.networkId())
.setSecurityGroups(openstackPort.securityGroups());
openstackPortInfoMap.put(portName, portBuilder.build());
......@@ -321,7 +334,6 @@ public class OpenstackSwitchingManager implements OpenstackSwitchingService {
securityGroupMap.put(sgId, openstackService.getSecurityGroup(sgId));
}
});
}
private void processHostRemoved(Host host) {
......@@ -440,6 +452,7 @@ public class OpenstackSwitchingManager implements OpenstackSwitchingService {
processPortRemoved((Device) deviceEvent.subject(), deviceEvent.port());
break;
default:
log.debug("Unsupported deviceEvent type {}", deviceEvent.type().toString());
break;
}
} else if (event instanceof HostEvent) {
......@@ -450,6 +463,7 @@ public class OpenstackSwitchingManager implements OpenstackSwitchingService {
processHostRemoved((Host) hostEvent.subject());
break;
default:
log.debug("Unsupported hostEvent type {}", hostEvent.type().toString());
break;
}
}
......