blob: f144e88edff9a1b5aa7322d91998c1c6375e996d [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;
33import org.onosproject.openstackinterface.OpenstackNetwork;
34import org.onosproject.openstackinterface.OpenstackPort;
35import org.onosproject.openstackinterface.OpenstackRouter;
sangho48907542016-03-28 16:07:07 +090036import org.onosproject.openstacknetworking.OpenstackNetworkingConfig;
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
54 protected PacketService packetService;
55
56 private final OpenstackRoutingRulePopulator rulePopulator;
57 private final int portNum;
58 private final OpenstackPort openstackPort;
Kyuhwi Choie2b37e32016-02-05 14:04:14 +090059 private final Port port;
sangho48907542016-03-28 16:07:07 +090060 private OpenstackNetworkingConfig config;
Kyuhwi Choie2b37e32016-02-05 14:04:14 +090061
62 private static final String DEVICE_OWNER_ROUTER_INTERFACE = "network:router_interface";
sangho0c2a3da2016-02-16 13:39:07 +090063
64 OpenstackPnatHandler(OpenstackRoutingRulePopulator rulePopulator, PacketContext context,
sangho48907542016-03-28 16:07:07 +090065 int portNum, OpenstackPort openstackPort, Port port, OpenstackNetworkingConfig config) {
sangho0c2a3da2016-02-16 13:39:07 +090066 this.rulePopulator = checkNotNull(rulePopulator);
67 this.context = checkNotNull(context);
68 this.portNum = checkNotNull(portNum);
69 this.openstackPort = checkNotNull(openstackPort);
Kyuhwi Choie2b37e32016-02-05 14:04:14 +090070 this.port = checkNotNull(port);
Kyuhwi Choiee9e3712016-02-22 22:49:36 +090071 this.config = checkNotNull(config);
sangho0c2a3da2016-02-16 13:39:07 +090072 }
73
74 @Override
75 public void run() {
76 InboundPacket inboundPacket = context.inPacket();
77 Ethernet ethernet = checkNotNull(inboundPacket.parsed());
78
79 //TODO: Considers IPV6
80 if (ethernet.getEtherType() != Ethernet.TYPE_IPV4) {
81 log.warn("Now, we just consider IP version 4");
82 return;
83 }
84
Kyuhwi Choie2b37e32016-02-05 14:04:14 +090085 OpenstackRouter router = getOpenstackRouter(openstackPort);
sangho0c2a3da2016-02-16 13:39:07 +090086
87 rulePopulator.populatePnatFlowRules(inboundPacket, openstackPort, portNum,
Kyuhwi Choiee9e3712016-02-22 22:49:36 +090088 getExternalIp(router), MacAddress.valueOf(config.gatewayExternalInterfaceMac()),
89 MacAddress.valueOf(config.physicalRouterMac()));
Kyuhwi Choie2b37e32016-02-05 14:04:14 +090090
91 packetOut((Ethernet) ethernet.clone(), inboundPacket.receivedFrom().deviceId(), portNum, router);
sangho0c2a3da2016-02-16 13:39:07 +090092 }
93
Kyuhwi Choie2b37e32016-02-05 14:04:14 +090094 private OpenstackRouter getOpenstackRouter(OpenstackPort openstackPort) {
sangho93447f12016-02-24 00:33:22 +090095 OpenstackInterfaceService networkingService = getService(OpenstackInterfaceService.class);
Kyuhwi Choie2b37e32016-02-05 14:04:14 +090096 OpenstackNetwork network = networkingService.network(openstackPort.networkId());
97
98 OpenstackPort port = networkingService.ports()
99 .stream()
100 .filter(p -> p.deviceOwner().equals(DEVICE_OWNER_ROUTER_INTERFACE))
101 .filter(p -> checkSameSubnet(p, openstackPort))
102 .findAny()
103 .orElse(null);
104
105 return checkNotNull(networkingService.router(port.deviceId()));
106 }
107
108 private boolean checkSameSubnet(OpenstackPort p, OpenstackPort openstackPort) {
109 String key1 = checkNotNull(p.fixedIps().keySet().stream().findFirst().orElse(null)).toString();
110 String key2 = checkNotNull(openstackPort.fixedIps().keySet().stream().findFirst().orElse(null)).toString();
111 return key1.equals(key2) ? true : false;
112 }
113
114 private Ip4Address getExternalIp(OpenstackRouter router) {
115 return router.gatewayExternalInfo().externalFixedIps().values().stream().findAny().orElse(null);
116 }
117
118 private void packetOut(Ethernet ethernet, DeviceId deviceId, int portNum, OpenstackRouter router) {
119 PacketService packetService = getService(PacketService.class);
120
sangho0c2a3da2016-02-16 13:39:07 +0900121 IPv4 iPacket = (IPv4) ethernet.getPayload();
122
123 TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder();
124
125 switch (iPacket.getProtocol()) {
126 case IPv4.PROTOCOL_TCP:
127 TCP tcpPacket = (TCP) iPacket.getPayload();
128 tcpPacket.setSourcePort(portNum);
129 tcpPacket.resetChecksum();
130 tcpPacket.setParent(iPacket);
131 iPacket.setPayload(tcpPacket);
132 break;
133 case IPv4.PROTOCOL_UDP:
134 UDP udpPacket = (UDP) iPacket.getPayload();
135 udpPacket.setSourcePort(portNum);
136 udpPacket.resetChecksum();
137 udpPacket.setParent(iPacket);
138 iPacket.setPayload(udpPacket);
139 break;
140 default:
Kyuhwi Choie2b37e32016-02-05 14:04:14 +0900141 log.error("Temporally, this method can process UDP and TCP protocol.");
142 return;
sangho0c2a3da2016-02-16 13:39:07 +0900143 }
144
Kyuhwi Choie2b37e32016-02-05 14:04:14 +0900145 iPacket.setSourceAddress(getExternalIp(router).toString());
sangho0c2a3da2016-02-16 13:39:07 +0900146 iPacket.resetChecksum();
Kyuhwi Choie2b37e32016-02-05 14:04:14 +0900147 iPacket.setParent(ethernet);
Kyuhwi Choiee9e3712016-02-22 22:49:36 +0900148 ethernet.setPayload(iPacket);
149 ethernet.setSourceMACAddress(config.gatewayExternalInterfaceMac())
150 .setDestinationMACAddress(config.physicalRouterMac());
sangho0c2a3da2016-02-16 13:39:07 +0900151 ethernet.resetChecksum();
152
Kyuhwi Choie2b37e32016-02-05 14:04:14 +0900153 treatment.setOutput(port.number());
sangho0c2a3da2016-02-16 13:39:07 +0900154
Kyuhwi Choie2b37e32016-02-05 14:04:14 +0900155 packetService.emit(new DefaultOutboundPacket(deviceId, treatment.build(),
156 ByteBuffer.wrap(ethernet.serialize())));
sangho0c2a3da2016-02-16 13:39:07 +0900157 }
sangho0c2a3da2016-02-16 13:39:07 +0900158}