Hyunsun Moon
Committed by Gerrit Code Review

CORD-416 Implemented ARP proxy for service IPs

Added ARP proxy which sends fake ARP reply for service IPs.

Change-Id: I0583ee994def2a429701c0375af5203bdfaa39c5
...@@ -23,6 +23,7 @@ import org.apache.felix.scr.annotations.Deactivate; ...@@ -23,6 +23,7 @@ import org.apache.felix.scr.annotations.Deactivate;
23 import org.apache.felix.scr.annotations.Reference; 23 import org.apache.felix.scr.annotations.Reference;
24 import org.apache.felix.scr.annotations.ReferenceCardinality; 24 import org.apache.felix.scr.annotations.ReferenceCardinality;
25 import org.apache.felix.scr.annotations.Service; 25 import org.apache.felix.scr.annotations.Service;
26 +import org.onlab.packet.Ethernet;
26 import org.onlab.packet.Ip4Address; 27 import org.onlab.packet.Ip4Address;
27 import org.onlab.util.ItemNotFoundException; 28 import org.onlab.util.ItemNotFoundException;
28 import org.onlab.packet.IpAddress; 29 import org.onlab.packet.IpAddress;
...@@ -56,6 +57,9 @@ import org.onosproject.net.group.GroupService; ...@@ -56,6 +57,9 @@ import org.onosproject.net.group.GroupService;
56 import org.onosproject.net.host.HostEvent; 57 import org.onosproject.net.host.HostEvent;
57 import org.onosproject.net.host.HostListener; 58 import org.onosproject.net.host.HostListener;
58 import org.onosproject.net.host.HostService; 59 import org.onosproject.net.host.HostService;
60 +import org.onosproject.net.packet.PacketContext;
61 +import org.onosproject.net.packet.PacketProcessor;
62 +import org.onosproject.net.packet.PacketService;
59 import org.onosproject.openstackswitching.OpenstackNetwork; 63 import org.onosproject.openstackswitching.OpenstackNetwork;
60 import org.onosproject.openstackswitching.OpenstackPort; 64 import org.onosproject.openstackswitching.OpenstackPort;
61 import org.onosproject.openstackswitching.OpenstackSubnet; 65 import org.onosproject.openstackswitching.OpenstackSubnet;
...@@ -135,6 +139,9 @@ public class CordVtn implements CordVtnService { ...@@ -135,6 +139,9 @@ public class CordVtn implements CordVtnService {
135 protected FlowRuleService flowRuleService; 139 protected FlowRuleService flowRuleService;
136 140
137 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) 141 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
142 + protected PacketService packetService;
143 +
144 + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
138 protected OvsdbController controller; 145 protected OvsdbController controller;
139 146
140 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) 147 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
...@@ -154,6 +161,7 @@ public class CordVtn implements CordVtnService { ...@@ -154,6 +161,7 @@ public class CordVtn implements CordVtnService {
154 161
155 private final DeviceListener deviceListener = new InternalDeviceListener(); 162 private final DeviceListener deviceListener = new InternalDeviceListener();
156 private final HostListener hostListener = new InternalHostListener(); 163 private final HostListener hostListener = new InternalHostListener();
164 + private final PacketProcessor packetProcessor = new InternalPacketProcessor();
157 165
158 private final OvsdbHandler ovsdbHandler = new OvsdbHandler(); 166 private final OvsdbHandler ovsdbHandler = new OvsdbHandler();
159 private final BridgeHandler bridgeHandler = new BridgeHandler(); 167 private final BridgeHandler bridgeHandler = new BridgeHandler();
...@@ -163,6 +171,7 @@ public class CordVtn implements CordVtnService { ...@@ -163,6 +171,7 @@ public class CordVtn implements CordVtnService {
163 private ConsistentMap<CordVtnNode, NodeState> nodeStore; 171 private ConsistentMap<CordVtnNode, NodeState> nodeStore;
164 private Map<HostId, OpenstackNetwork> hostNetMap = Maps.newHashMap(); 172 private Map<HostId, OpenstackNetwork> hostNetMap = Maps.newHashMap();
165 private CordVtnRuleInstaller ruleInstaller; 173 private CordVtnRuleInstaller ruleInstaller;
174 + private CordVtnArpProxy arpProxy;
166 175
167 private enum NodeState { 176 private enum NodeState {
168 177
...@@ -223,6 +232,10 @@ public class CordVtn implements CordVtnService { ...@@ -223,6 +232,10 @@ public class CordVtn implements CordVtnService {
223 mastershipService, 232 mastershipService,
224 DEFAULT_TUNNEL); 233 DEFAULT_TUNNEL);
225 234
235 + arpProxy = new CordVtnArpProxy(appId, packetService);
236 + packetService.addProcessor(packetProcessor, PacketProcessor.director(0));
237 + arpProxy.requestPacket();
238 +
226 deviceService.addListener(deviceListener); 239 deviceService.addListener(deviceListener);
227 hostService.addListener(hostListener); 240 hostService.addListener(hostListener);
228 241
...@@ -233,6 +246,7 @@ public class CordVtn implements CordVtnService { ...@@ -233,6 +246,7 @@ public class CordVtn implements CordVtnService {
233 protected void deactivate() { 246 protected void deactivate() {
234 deviceService.removeListener(deviceListener); 247 deviceService.removeListener(deviceListener);
235 hostService.removeListener(hostListener); 248 hostService.removeListener(hostListener);
249 + packetService.removeProcessor(packetProcessor);
236 250
237 eventExecutor.shutdown(); 251 eventExecutor.shutdown();
238 nodeStore.clear(); 252 nodeStore.clear();
...@@ -920,17 +934,18 @@ public class CordVtn implements CordVtnService { ...@@ -920,17 +934,18 @@ public class CordVtn implements CordVtnService {
920 log.info("VM {} is detected", host.id()); 934 log.info("VM {} is detected", host.id());
921 hostNetMap.put(host.id(), vNet); 935 hostNetMap.put(host.id(), vNet);
922 936
937 + CordService service = getCordService(vNet);
938 + if (service != null) {
939 + // TODO check if the service needs an update on its group buckets after done CORD-433
940 + ruleInstaller.updateServiceGroup(service);
941 + arpProxy.addServiceIp(service.serviceIp());
942 + }
943 +
923 ruleInstaller.populateBasicConnectionRules( 944 ruleInstaller.populateBasicConnectionRules(
924 host, 945 host,
925 hostIp, 946 hostIp,
926 checkNotNull(getRemoteIp(host.location().deviceId())).getIp4Address(), 947 checkNotNull(getRemoteIp(host.location().deviceId())).getIp4Address(),
927 vNet); 948 vNet);
928 -
929 - CordService service = getCordService(vNet);
930 - // TODO check if the service needs an update on its group buckets after done CORD-433
931 - if (service != null) {
932 - ruleInstaller.updateServiceGroup(service);
933 - }
934 } 949 }
935 950
936 @Override 951 @Override
...@@ -950,12 +965,37 @@ public class CordVtn implements CordVtnService { ...@@ -950,12 +965,37 @@ public class CordVtn implements CordVtnService {
950 ruleInstaller.removeBasicConnectionRules(host); 965 ruleInstaller.removeBasicConnectionRules(host);
951 966
952 CordService service = getCordService(vNet); 967 CordService service = getCordService(vNet);
953 - // TODO check if the service needs an update on its group buckets after done CORD-433
954 if (service != null) { 968 if (service != null) {
969 + // TODO check if the service needs an update on its group buckets after done CORD-433
955 ruleInstaller.updateServiceGroup(service); 970 ruleInstaller.updateServiceGroup(service);
971 +
972 + if (getHostsWithOpenstackNetwork(vNet).isEmpty()) {
973 + arpProxy.removeServiceIp(service.serviceIp());
974 + }
956 } 975 }
957 976
958 hostNetMap.remove(host.id()); 977 hostNetMap.remove(host.id());
959 } 978 }
960 } 979 }
980 +
981 + private class InternalPacketProcessor implements PacketProcessor {
982 +
983 + @Override
984 + public void process(PacketContext context) {
985 + if (context.isHandled()) {
986 + return;
987 + }
988 +
989 + Ethernet ethPacket = context.inPacket().parsed();
990 + if (ethPacket == null) {
991 + return;
992 + }
993 +
994 + if (ethPacket.getEtherType() != Ethernet.TYPE_ARP) {
995 + return;
996 + }
997 +
998 + arpProxy.processArpPacket(context, ethPacket);
999 + }
1000 + }
961 } 1001 }
......
1 +/*
2 + * Copyright 2014-2015 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 + */
16 +package org.onosproject.cordvtn;
17 +
18 +import com.google.common.collect.Sets;
19 +import org.onlab.packet.ARP;
20 +import org.onlab.packet.EthType;
21 +import org.onlab.packet.Ethernet;
22 +import org.onlab.packet.Ip4Address;
23 +import org.onlab.packet.IpAddress;
24 +import org.onlab.packet.MacAddress;
25 +import org.onosproject.core.ApplicationId;
26 +import org.onosproject.net.flow.DefaultTrafficSelector;
27 +import org.onosproject.net.flow.DefaultTrafficTreatment;
28 +import org.onosproject.net.flow.TrafficSelector;
29 +import org.onosproject.net.flow.TrafficTreatment;
30 +import org.onosproject.net.packet.DefaultOutboundPacket;
31 +import org.onosproject.net.packet.PacketContext;
32 +import org.onosproject.net.packet.PacketPriority;
33 +import org.onosproject.net.packet.PacketService;
34 +import org.slf4j.Logger;
35 +
36 +import java.nio.ByteBuffer;
37 +import java.util.Optional;
38 +import java.util.Set;
39 +
40 +import static com.google.common.base.Preconditions.checkNotNull;
41 +import static org.slf4j.LoggerFactory.getLogger;
42 +
43 +/**
44 + * Handles ARP requests for virtual network service IPs.
45 + */
46 +public class CordVtnArpProxy {
47 + protected final Logger log = getLogger(getClass());
48 + // TODO make gateway MAC address configurable
49 + private static final MacAddress DEFAULT_GATEWAY_MAC = MacAddress.valueOf("00:00:00:00:00:01");
50 +
51 + private final ApplicationId appId;
52 + private final PacketService packetService;
53 +
54 + private Set<Ip4Address> serviceIPs = Sets.newHashSet();
55 +
56 + /**
57 + * Default constructor.
58 + *
59 + * @param appId application id
60 + * @param packetService packet service
61 + */
62 + public CordVtnArpProxy(ApplicationId appId, PacketService packetService) {
63 + this.appId = appId;
64 + this.packetService = packetService;
65 + }
66 +
67 + /**
68 + * Requests ARP packet.
69 + */
70 + public void requestPacket() {
71 + TrafficSelector selector = DefaultTrafficSelector.builder()
72 + .matchEthType(EthType.EtherType.ARP.ethType().toShort())
73 + .build();
74 +
75 + packetService.requestPackets(selector,
76 + PacketPriority.CONTROL,
77 + appId,
78 + Optional.empty());
79 + }
80 +
81 + /**
82 + * Cancels ARP packet.
83 + */
84 + public void cancelPacket() {
85 + TrafficSelector selector = DefaultTrafficSelector.builder()
86 + .matchEthType(EthType.EtherType.ARP.ethType().toShort())
87 + .build();
88 +
89 + packetService.cancelPackets(selector,
90 + PacketPriority.CONTROL,
91 + appId,
92 + Optional.empty());
93 + }
94 +
95 + /**
96 + * Adds a given service IP address to be served.
97 + *
98 + * @param serviceIp service ip
99 + */
100 + public void addServiceIp(IpAddress serviceIp) {
101 + checkNotNull(serviceIp);
102 + serviceIPs.add(serviceIp.getIp4Address());
103 + }
104 +
105 + /**
106 + * Removes a given service IP address from this ARP proxy.
107 + *
108 + * @param serviceIp service ip
109 + */
110 + public void removeServiceIp(IpAddress serviceIp) {
111 + checkNotNull(serviceIp);
112 + serviceIPs.remove(serviceIp.getIp4Address());
113 + }
114 +
115 + /**
116 + * Emits ARP reply with fake MAC address for a given ARP request.
117 + * It only handles requests for the registered service IPs, and the other
118 + * requests can be handled by other ARP handlers like openstackSwitching or
119 + * proxyArp, for example.
120 + *
121 + * @param context packet context
122 + * @param ethPacket ethernet packet
123 + */
124 + public void processArpPacket(PacketContext context, Ethernet ethPacket) {
125 + ARP arpPacket = (ARP) ethPacket.getPayload();
126 + Ip4Address targetIp = Ip4Address.valueOf(arpPacket.getTargetProtocolAddress());
127 +
128 + if (arpPacket.getOpCode() != ARP.OP_REQUEST) {
129 + return;
130 + }
131 +
132 + if (!serviceIPs.contains(targetIp)) {
133 + return;
134 + }
135 +
136 + Ethernet ethReply = ARP.buildArpReply(
137 + targetIp,
138 + DEFAULT_GATEWAY_MAC,
139 + ethPacket);
140 +
141 + TrafficTreatment treatment = DefaultTrafficTreatment.builder()
142 + .setOutput(context.inPacket().receivedFrom().port())
143 + .build();
144 +
145 + packetService.emit(new DefaultOutboundPacket(
146 + context.inPacket().receivedFrom().deviceId(),
147 + treatment,
148 + ByteBuffer.wrap(ethReply.serialize())));
149 +
150 + context.block();
151 + }
152 +}