blob: 3f11e6cef263fb626a8319647c25473c29b40449 [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;
sangho48907542016-03-28 16:07:07 +090035import org.onosproject.openstacknetworking.OpenstackNetworkingConfig;
Kyuhwi Choi92d9ea42016-06-13 17:28:00 +090036import org.onosproject.scalablegateway.api.GatewayNode;
37import org.onosproject.scalablegateway.api.ScalableGatewayService;
sangho0c2a3da2016-02-16 13:39:07 +090038import org.slf4j.Logger;
39import org.slf4j.LoggerFactory;
40
41import java.nio.ByteBuffer;
42
43import static com.google.common.base.Preconditions.checkNotNull;
Kyuhwi Choie2b37e32016-02-05 14:04:14 +090044import static org.onlab.osgi.DefaultServiceDirectory.getService;
sangho0c2a3da2016-02-16 13:39:07 +090045
46
47/**
48 * Handle NAT packet processing for Managing Flow Rules In Openstack Nodes.
49 */
50public class OpenstackPnatHandler implements Runnable {
51
52 volatile PacketContext context;
53 private final Logger log = LoggerFactory.getLogger(getClass());
54
55 protected PacketService packetService;
56
57 private final OpenstackRoutingRulePopulator rulePopulator;
58 private final int portNum;
59 private final OpenstackPort openstackPort;
Kyuhwi Choie2b37e32016-02-05 14:04:14 +090060 private final Port port;
sangho48907542016-03-28 16:07:07 +090061 private OpenstackNetworkingConfig config;
Kyuhwi Choie2b37e32016-02-05 14:04:14 +090062
63 private static final String DEVICE_OWNER_ROUTER_INTERFACE = "network:router_interface";
Kyuhwi Choi92d9ea42016-06-13 17:28:00 +090064 private static final String EXTERNAL_PORT_NULL = "There is no external port in this deviceId []";
sangho0c2a3da2016-02-16 13:39:07 +090065
66 OpenstackPnatHandler(OpenstackRoutingRulePopulator rulePopulator, PacketContext context,
sangho48907542016-03-28 16:07:07 +090067 int portNum, OpenstackPort openstackPort, Port port, OpenstackNetworkingConfig config) {
sangho0c2a3da2016-02-16 13:39:07 +090068 this.rulePopulator = checkNotNull(rulePopulator);
69 this.context = checkNotNull(context);
70 this.portNum = checkNotNull(portNum);
71 this.openstackPort = checkNotNull(openstackPort);
Kyuhwi Choie2b37e32016-02-05 14:04:14 +090072 this.port = checkNotNull(port);
Kyuhwi Choiee9e3712016-02-22 22:49:36 +090073 this.config = checkNotNull(config);
sangho0c2a3da2016-02-16 13:39:07 +090074 }
75
76 @Override
77 public void run() {
78 InboundPacket inboundPacket = context.inPacket();
79 Ethernet ethernet = checkNotNull(inboundPacket.parsed());
80
81 //TODO: Considers IPV6
82 if (ethernet.getEtherType() != Ethernet.TYPE_IPV4) {
83 log.warn("Now, we just consider IP version 4");
84 return;
85 }
86
Kyuhwi Choie2b37e32016-02-05 14:04:14 +090087 OpenstackRouter router = getOpenstackRouter(openstackPort);
sangho0c2a3da2016-02-16 13:39:07 +090088
Kyuhwi Choi92d9ea42016-06-13 17:28:00 +090089 MacAddress externalMac = MacAddress.NONE;
90 MacAddress routerMac = MacAddress.NONE;
91
sangho0c2a3da2016-02-16 13:39:07 +090092 rulePopulator.populatePnatFlowRules(inboundPacket, openstackPort, portNum,
Kyuhwi Choi92d9ea42016-06-13 17:28:00 +090093 getExternalIp(router), externalMac, routerMac);
Kyuhwi Choie2b37e32016-02-05 14:04:14 +090094
95 packetOut((Ethernet) ethernet.clone(), inboundPacket.receivedFrom().deviceId(), portNum, router);
sangho0c2a3da2016-02-16 13:39:07 +090096 }
97
Kyuhwi Choie2b37e32016-02-05 14:04:14 +090098 private OpenstackRouter getOpenstackRouter(OpenstackPort openstackPort) {
sangho93447f12016-02-24 00:33:22 +090099 OpenstackInterfaceService networkingService = getService(OpenstackInterfaceService.class);
Kyuhwi Choie2b37e32016-02-05 14:04:14 +0900100
101 OpenstackPort port = networkingService.ports()
102 .stream()
103 .filter(p -> p.deviceOwner().equals(DEVICE_OWNER_ROUTER_INTERFACE))
104 .filter(p -> checkSameSubnet(p, openstackPort))
105 .findAny()
106 .orElse(null);
107
108 return checkNotNull(networkingService.router(port.deviceId()));
109 }
110
111 private boolean checkSameSubnet(OpenstackPort p, OpenstackPort openstackPort) {
112 String key1 = checkNotNull(p.fixedIps().keySet().stream().findFirst().orElse(null)).toString();
113 String key2 = checkNotNull(openstackPort.fixedIps().keySet().stream().findFirst().orElse(null)).toString();
114 return key1.equals(key2) ? true : false;
115 }
116
117 private Ip4Address getExternalIp(OpenstackRouter router) {
118 return router.gatewayExternalInfo().externalFixedIps().values().stream().findAny().orElse(null);
119 }
120
121 private void packetOut(Ethernet ethernet, DeviceId deviceId, int portNum, OpenstackRouter router) {
122 PacketService packetService = getService(PacketService.class);
123
sangho0c2a3da2016-02-16 13:39:07 +0900124 IPv4 iPacket = (IPv4) ethernet.getPayload();
125
126 TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder();
127
128 switch (iPacket.getProtocol()) {
129 case IPv4.PROTOCOL_TCP:
130 TCP tcpPacket = (TCP) iPacket.getPayload();
131 tcpPacket.setSourcePort(portNum);
132 tcpPacket.resetChecksum();
133 tcpPacket.setParent(iPacket);
134 iPacket.setPayload(tcpPacket);
135 break;
136 case IPv4.PROTOCOL_UDP:
137 UDP udpPacket = (UDP) iPacket.getPayload();
138 udpPacket.setSourcePort(portNum);
139 udpPacket.resetChecksum();
140 udpPacket.setParent(iPacket);
141 iPacket.setPayload(udpPacket);
142 break;
143 default:
Kyuhwi Choie2b37e32016-02-05 14:04:14 +0900144 log.error("Temporally, this method can process UDP and TCP protocol.");
145 return;
sangho0c2a3da2016-02-16 13:39:07 +0900146 }
147
Kyuhwi Choie2b37e32016-02-05 14:04:14 +0900148 iPacket.setSourceAddress(getExternalIp(router).toString());
sangho0c2a3da2016-02-16 13:39:07 +0900149 iPacket.resetChecksum();
Kyuhwi Choie2b37e32016-02-05 14:04:14 +0900150 iPacket.setParent(ethernet);
Kyuhwi Choiee9e3712016-02-22 22:49:36 +0900151 ethernet.setPayload(iPacket);
Kyuhwi Choi92d9ea42016-06-13 17:28:00 +0900152 ScalableGatewayService gatewayService = getService(ScalableGatewayService.class);
153 GatewayNode gatewayNode = gatewayService.getGatewayNode(deviceId);
154 if (gatewayNode.getGatewayExternalInterfaceNames().size() == 0) {
155 log.error(EXTERNAL_PORT_NULL, deviceId.toString());
156 return;
157 }
158 treatment.setOutput(gatewayService.getGatewayExternalPorts(deviceId).get(0));
159
sangho0c2a3da2016-02-16 13:39:07 +0900160 ethernet.resetChecksum();
161
sangho0c2a3da2016-02-16 13:39:07 +0900162
Kyuhwi Choie2b37e32016-02-05 14:04:14 +0900163 packetService.emit(new DefaultOutboundPacket(deviceId, treatment.build(),
164 ByteBuffer.wrap(ethernet.serialize())));
sangho0c2a3da2016-02-16 13:39:07 +0900165 }
sangho0c2a3da2016-02-16 13:39:07 +0900166}