blob: 137c090034299d0967ab62ef8d9b0c860f23c36b [file] [log] [blame]
sangho0c2a3da2016-02-16 13:39:07 +09001/*
Brian O'Connor5ab426f2016-04-09 01:19:45 -07002 * Copyright 2016-present Open Networking Laboratory
sangho0c2a3da2016-02-16 13:39:07 +09003 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16package org.onosproject.openstacknetworking.routing;
17
18import org.onlab.packet.Ethernet;
19import org.onlab.packet.IPv4;
Kyuhwi Choie2b37e32016-02-05 14:04:14 +090020import org.onlab.packet.Ip4Address;
sangho0c2a3da2016-02-16 13:39:07 +090021import org.onlab.packet.MacAddress;
22import org.onlab.packet.TCP;
23import org.onlab.packet.UDP;
24import org.onosproject.net.DeviceId;
Kyuhwi Choie2b37e32016-02-05 14:04:14 +090025import org.onosproject.net.Port;
sangho0c2a3da2016-02-16 13:39:07 +090026import org.onosproject.net.flow.DefaultTrafficTreatment;
27import org.onosproject.net.flow.TrafficTreatment;
28import org.onosproject.net.packet.DefaultOutboundPacket;
29import org.onosproject.net.packet.InboundPacket;
30import org.onosproject.net.packet.PacketContext;
31import org.onosproject.net.packet.PacketService;
sangho93447f12016-02-24 00:33:22 +090032import org.onosproject.openstackinterface.OpenstackInterfaceService;
sangho93447f12016-02-24 00:33:22 +090033import org.onosproject.openstackinterface.OpenstackPort;
34import org.onosproject.openstackinterface.OpenstackRouter;
Kyuhwi Choi92d9ea42016-06-13 17:28:00 +090035import org.onosproject.scalablegateway.api.GatewayNode;
36import org.onosproject.scalablegateway.api.ScalableGatewayService;
sangho0c2a3da2016-02-16 13:39:07 +090037import org.slf4j.Logger;
38import org.slf4j.LoggerFactory;
39
40import java.nio.ByteBuffer;
41
42import static com.google.common.base.Preconditions.checkNotNull;
Kyuhwi Choie2b37e32016-02-05 14:04:14 +090043import static org.onlab.osgi.DefaultServiceDirectory.getService;
sangho0c2a3da2016-02-16 13:39:07 +090044
45
46/**
47 * Handle NAT packet processing for Managing Flow Rules In Openstack Nodes.
48 */
49public class OpenstackPnatHandler implements Runnable {
50
51 volatile PacketContext context;
52 private final Logger log = LoggerFactory.getLogger(getClass());
53
sangho0c2a3da2016-02-16 13:39:07 +090054 private final OpenstackRoutingRulePopulator rulePopulator;
55 private final int portNum;
56 private final OpenstackPort openstackPort;
Kyuhwi Choie2b37e32016-02-05 14:04:14 +090057 private final Port port;
58
59 private static final String DEVICE_OWNER_ROUTER_INTERFACE = "network:router_interface";
Kyuhwi Choi92d9ea42016-06-13 17:28:00 +090060 private static final String EXTERNAL_PORT_NULL = "There is no external port in this deviceId []";
sangho0c2a3da2016-02-16 13:39:07 +090061
62 OpenstackPnatHandler(OpenstackRoutingRulePopulator rulePopulator, PacketContext context,
sangho6032f342016-07-07 14:32:03 +090063 int portNum, OpenstackPort openstackPort, Port port) {
sangho0c2a3da2016-02-16 13:39:07 +090064 this.rulePopulator = checkNotNull(rulePopulator);
65 this.context = checkNotNull(context);
66 this.portNum = checkNotNull(portNum);
67 this.openstackPort = checkNotNull(openstackPort);
Kyuhwi Choie2b37e32016-02-05 14:04:14 +090068 this.port = checkNotNull(port);
sangho0c2a3da2016-02-16 13:39:07 +090069 }
70
71 @Override
72 public void run() {
73 InboundPacket inboundPacket = context.inPacket();
74 Ethernet ethernet = checkNotNull(inboundPacket.parsed());
75
76 //TODO: Considers IPV6
77 if (ethernet.getEtherType() != Ethernet.TYPE_IPV4) {
78 log.warn("Now, we just consider IP version 4");
79 return;
80 }
81
Kyuhwi Choie2b37e32016-02-05 14:04:14 +090082 OpenstackRouter router = getOpenstackRouter(openstackPort);
sangho0c2a3da2016-02-16 13:39:07 +090083
Kyuhwi Choi92d9ea42016-06-13 17:28:00 +090084 MacAddress externalMac = MacAddress.NONE;
85 MacAddress routerMac = MacAddress.NONE;
86
sangho0c2a3da2016-02-16 13:39:07 +090087 rulePopulator.populatePnatFlowRules(inboundPacket, openstackPort, portNum,
Kyuhwi Choi92d9ea42016-06-13 17:28:00 +090088 getExternalIp(router), externalMac, routerMac);
Kyuhwi Choie2b37e32016-02-05 14:04:14 +090089
90 packetOut((Ethernet) ethernet.clone(), inboundPacket.receivedFrom().deviceId(), portNum, router);
sangho0c2a3da2016-02-16 13:39:07 +090091 }
92
Kyuhwi Choie2b37e32016-02-05 14:04:14 +090093 private OpenstackRouter getOpenstackRouter(OpenstackPort openstackPort) {
sangho93447f12016-02-24 00:33:22 +090094 OpenstackInterfaceService networkingService = getService(OpenstackInterfaceService.class);
Kyuhwi Choie2b37e32016-02-05 14:04:14 +090095
96 OpenstackPort port = networkingService.ports()
97 .stream()
98 .filter(p -> p.deviceOwner().equals(DEVICE_OWNER_ROUTER_INTERFACE))
99 .filter(p -> checkSameSubnet(p, openstackPort))
100 .findAny()
101 .orElse(null);
102
103 return checkNotNull(networkingService.router(port.deviceId()));
104 }
105
106 private boolean checkSameSubnet(OpenstackPort p, OpenstackPort openstackPort) {
107 String key1 = checkNotNull(p.fixedIps().keySet().stream().findFirst().orElse(null)).toString();
108 String key2 = checkNotNull(openstackPort.fixedIps().keySet().stream().findFirst().orElse(null)).toString();
109 return key1.equals(key2) ? true : false;
110 }
111
112 private Ip4Address getExternalIp(OpenstackRouter router) {
113 return router.gatewayExternalInfo().externalFixedIps().values().stream().findAny().orElse(null);
114 }
115
116 private void packetOut(Ethernet ethernet, DeviceId deviceId, int portNum, OpenstackRouter router) {
117 PacketService packetService = getService(PacketService.class);
118
sangho0c2a3da2016-02-16 13:39:07 +0900119 IPv4 iPacket = (IPv4) ethernet.getPayload();
120
121 TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder();
122
123 switch (iPacket.getProtocol()) {
124 case IPv4.PROTOCOL_TCP:
125 TCP tcpPacket = (TCP) iPacket.getPayload();
126 tcpPacket.setSourcePort(portNum);
127 tcpPacket.resetChecksum();
128 tcpPacket.setParent(iPacket);
129 iPacket.setPayload(tcpPacket);
130 break;
131 case IPv4.PROTOCOL_UDP:
132 UDP udpPacket = (UDP) iPacket.getPayload();
133 udpPacket.setSourcePort(portNum);
134 udpPacket.resetChecksum();
135 udpPacket.setParent(iPacket);
136 iPacket.setPayload(udpPacket);
137 break;
138 default:
Kyuhwi Choie2b37e32016-02-05 14:04:14 +0900139 log.error("Temporally, this method can process UDP and TCP protocol.");
140 return;
sangho0c2a3da2016-02-16 13:39:07 +0900141 }
142
Kyuhwi Choie2b37e32016-02-05 14:04:14 +0900143 iPacket.setSourceAddress(getExternalIp(router).toString());
sangho0c2a3da2016-02-16 13:39:07 +0900144 iPacket.resetChecksum();
Kyuhwi Choie2b37e32016-02-05 14:04:14 +0900145 iPacket.setParent(ethernet);
Kyuhwi Choiee9e3712016-02-22 22:49:36 +0900146 ethernet.setPayload(iPacket);
sangho6032f342016-07-07 14:32:03 +0900147
Kyuhwi Choi92d9ea42016-06-13 17:28:00 +0900148 ScalableGatewayService gatewayService = getService(ScalableGatewayService.class);
149 GatewayNode gatewayNode = gatewayService.getGatewayNode(deviceId);
Kyuhwi Choi176c83d2016-07-14 11:39:37 +0900150 if (gatewayNode.getGatewayExternalInterfaceName() == null) {
Kyuhwi Choi92d9ea42016-06-13 17:28:00 +0900151 log.error(EXTERNAL_PORT_NULL, deviceId.toString());
152 return;
153 }
Kyuhwi Choi176c83d2016-07-14 11:39:37 +0900154 treatment.setOutput(gatewayService.getGatewayExternalPort(deviceId));
Kyuhwi Choi92d9ea42016-06-13 17:28:00 +0900155
sangho0c2a3da2016-02-16 13:39:07 +0900156 ethernet.resetChecksum();
157
Kyuhwi Choie2b37e32016-02-05 14:04:14 +0900158 packetService.emit(new DefaultOutboundPacket(deviceId, treatment.build(),
159 ByteBuffer.wrap(ethernet.serialize())));
sangho0c2a3da2016-02-16 13:39:07 +0900160 }
sangho0c2a3da2016-02-16 13:39:07 +0900161}