blob: 2912d7d88bb656ebee08c1b99552092d163c5212 [file] [log] [blame]
sangho0c2a3da2016-02-16 13:39:07 +09001/*
2 * Copyright 2016 Open Networking Laboratory
3 *
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;
sangho0c2a3da2016-02-16 13:39:07 +090036import org.slf4j.Logger;
37import org.slf4j.LoggerFactory;
38
39import java.nio.ByteBuffer;
40
41import static com.google.common.base.Preconditions.checkNotNull;
Kyuhwi Choie2b37e32016-02-05 14:04:14 +090042import static org.onlab.osgi.DefaultServiceDirectory.getService;
sangho0c2a3da2016-02-16 13:39:07 +090043
44
45/**
46 * Handle NAT packet processing for Managing Flow Rules In Openstack Nodes.
47 */
48public class OpenstackPnatHandler implements Runnable {
49
50 volatile PacketContext context;
51 private final Logger log = LoggerFactory.getLogger(getClass());
52
53 protected PacketService packetService;
54
55 private final OpenstackRoutingRulePopulator rulePopulator;
56 private final int portNum;
57 private final OpenstackPort openstackPort;
Kyuhwi Choie2b37e32016-02-05 14:04:14 +090058 private final Port port;
Kyuhwi Choiee9e3712016-02-22 22:49:36 +090059 private OpenstackRoutingConfig config;
Kyuhwi Choie2b37e32016-02-05 14:04:14 +090060
61 private static final String DEVICE_OWNER_ROUTER_INTERFACE = "network:router_interface";
sangho0c2a3da2016-02-16 13:39:07 +090062
63 OpenstackPnatHandler(OpenstackRoutingRulePopulator rulePopulator, PacketContext context,
Kyuhwi Choiee9e3712016-02-22 22:49:36 +090064 int portNum, OpenstackPort openstackPort, Port port, OpenstackRoutingConfig config) {
sangho0c2a3da2016-02-16 13:39:07 +090065 this.rulePopulator = checkNotNull(rulePopulator);
66 this.context = checkNotNull(context);
67 this.portNum = checkNotNull(portNum);
68 this.openstackPort = checkNotNull(openstackPort);
Kyuhwi Choie2b37e32016-02-05 14:04:14 +090069 this.port = checkNotNull(port);
Kyuhwi Choiee9e3712016-02-22 22:49:36 +090070 this.config = checkNotNull(config);
sangho0c2a3da2016-02-16 13:39:07 +090071 }
72
73 @Override
74 public void run() {
75 InboundPacket inboundPacket = context.inPacket();
76 Ethernet ethernet = checkNotNull(inboundPacket.parsed());
77
78 //TODO: Considers IPV6
79 if (ethernet.getEtherType() != Ethernet.TYPE_IPV4) {
80 log.warn("Now, we just consider IP version 4");
81 return;
82 }
83
Kyuhwi Choie2b37e32016-02-05 14:04:14 +090084 OpenstackRouter router = getOpenstackRouter(openstackPort);
sangho0c2a3da2016-02-16 13:39:07 +090085
86 rulePopulator.populatePnatFlowRules(inboundPacket, openstackPort, portNum,
Kyuhwi Choiee9e3712016-02-22 22:49:36 +090087 getExternalIp(router), MacAddress.valueOf(config.gatewayExternalInterfaceMac()),
88 MacAddress.valueOf(config.physicalRouterMac()));
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 OpenstackNetwork network = networkingService.network(openstackPort.networkId());
96
97 OpenstackPort port = networkingService.ports()
98 .stream()
99 .filter(p -> p.deviceOwner().equals(DEVICE_OWNER_ROUTER_INTERFACE))
100 .filter(p -> checkSameSubnet(p, openstackPort))
101 .findAny()
102 .orElse(null);
103
104 return checkNotNull(networkingService.router(port.deviceId()));
105 }
106
107 private boolean checkSameSubnet(OpenstackPort p, OpenstackPort openstackPort) {
108 String key1 = checkNotNull(p.fixedIps().keySet().stream().findFirst().orElse(null)).toString();
109 String key2 = checkNotNull(openstackPort.fixedIps().keySet().stream().findFirst().orElse(null)).toString();
110 return key1.equals(key2) ? true : false;
111 }
112
113 private Ip4Address getExternalIp(OpenstackRouter router) {
114 return router.gatewayExternalInfo().externalFixedIps().values().stream().findAny().orElse(null);
115 }
116
117 private void packetOut(Ethernet ethernet, DeviceId deviceId, int portNum, OpenstackRouter router) {
118 PacketService packetService = getService(PacketService.class);
119
sangho0c2a3da2016-02-16 13:39:07 +0900120 IPv4 iPacket = (IPv4) ethernet.getPayload();
121
122 TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder();
123
124 switch (iPacket.getProtocol()) {
125 case IPv4.PROTOCOL_TCP:
126 TCP tcpPacket = (TCP) iPacket.getPayload();
127 tcpPacket.setSourcePort(portNum);
128 tcpPacket.resetChecksum();
129 tcpPacket.setParent(iPacket);
130 iPacket.setPayload(tcpPacket);
131 break;
132 case IPv4.PROTOCOL_UDP:
133 UDP udpPacket = (UDP) iPacket.getPayload();
134 udpPacket.setSourcePort(portNum);
135 udpPacket.resetChecksum();
136 udpPacket.setParent(iPacket);
137 iPacket.setPayload(udpPacket);
138 break;
139 default:
Kyuhwi Choie2b37e32016-02-05 14:04:14 +0900140 log.error("Temporally, this method can process UDP and TCP protocol.");
141 return;
sangho0c2a3da2016-02-16 13:39:07 +0900142 }
143
Kyuhwi Choie2b37e32016-02-05 14:04:14 +0900144 iPacket.setSourceAddress(getExternalIp(router).toString());
sangho0c2a3da2016-02-16 13:39:07 +0900145 iPacket.resetChecksum();
Kyuhwi Choie2b37e32016-02-05 14:04:14 +0900146 iPacket.setParent(ethernet);
Kyuhwi Choiee9e3712016-02-22 22:49:36 +0900147 ethernet.setPayload(iPacket);
148 ethernet.setSourceMACAddress(config.gatewayExternalInterfaceMac())
149 .setDestinationMACAddress(config.physicalRouterMac());
sangho0c2a3da2016-02-16 13:39:07 +0900150 ethernet.resetChecksum();
151
Kyuhwi Choie2b37e32016-02-05 14:04:14 +0900152 treatment.setOutput(port.number());
sangho0c2a3da2016-02-16 13:39:07 +0900153
Kyuhwi Choie2b37e32016-02-05 14:04:14 +0900154 packetService.emit(new DefaultOutboundPacket(deviceId, treatment.build(),
155 ByteBuffer.wrap(ethernet.serialize())));
sangho0c2a3da2016-02-16 13:39:07 +0900156 }
sangho0c2a3da2016-02-16 13:39:07 +0900157}