blob: ae766ba164107a4e4a425eaa27c20e753f342d6b [file] [log] [blame]
Jian Li451cea32016-10-04 15:27:50 +09001/*
2 * Copyright 2016-present 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 */
Jian Li5e505c62016-12-05 02:44:24 +090016package org.onosproject.lisp.ctl.impl;
Jian Li451cea32016-10-04 15:27:50 +090017
Jian Lib86d8ad2017-05-03 02:53:44 +090018import com.google.common.collect.ImmutableList;
Jian Li6ef1b3f2016-11-12 18:16:06 +090019import org.onlab.packet.IpAddress;
Jian Lib86d8ad2017-05-03 02:53:44 +090020import org.onosproject.lisp.ctl.LispRouter;
21import org.onosproject.lisp.ctl.LispRouterFactory;
22import org.onosproject.lisp.ctl.impl.util.LispMapUtil;
Jian Li712ec052016-11-22 03:23:54 +090023import org.onosproject.lisp.msg.authentication.LispAuthenticationConfig;
Jian Li5e505c62016-12-05 02:44:24 +090024import org.onosproject.lisp.msg.protocols.DefaultLispInfoReply.DefaultInfoReplyBuilder;
25import org.onosproject.lisp.msg.protocols.DefaultLispInfoRequest.DefaultInfoRequestBuilder;
Jian Li24f6cc02016-11-01 16:38:40 +090026import org.onosproject.lisp.msg.protocols.DefaultLispMapNotify.DefaultNotifyBuilder;
27import org.onosproject.lisp.msg.protocols.DefaultLispMapRegister.DefaultRegisterBuilder;
Jian Lib86d8ad2017-05-03 02:53:44 +090028import org.onosproject.lisp.msg.protocols.DefaultLispMapRequest.DefaultRequestBuilder;
Jian Li24f6cc02016-11-01 16:38:40 +090029import org.onosproject.lisp.msg.protocols.LispEidRecord;
Jian Li6ef1b3f2016-11-12 18:16:06 +090030import org.onosproject.lisp.msg.protocols.LispInfoReply;
31import org.onosproject.lisp.msg.protocols.LispInfoReply.InfoReplyBuilder;
32import org.onosproject.lisp.msg.protocols.LispInfoRequest;
33import org.onosproject.lisp.msg.protocols.LispInfoRequest.InfoRequestBuilder;
Jian Liafe2d3f2016-11-01 02:49:07 +090034import org.onosproject.lisp.msg.protocols.LispMapNotify;
Jian Li24f6cc02016-11-01 16:38:40 +090035import org.onosproject.lisp.msg.protocols.LispMapNotify.NotifyBuilder;
Jian Lib86d8ad2017-05-03 02:53:44 +090036import org.onosproject.lisp.msg.protocols.LispMapRecord;
Jian Li24f6cc02016-11-01 16:38:40 +090037import org.onosproject.lisp.msg.protocols.LispMapRegister;
38import org.onosproject.lisp.msg.protocols.LispMapRegister.RegisterBuilder;
Jian Lib86d8ad2017-05-03 02:53:44 +090039import org.onosproject.lisp.msg.protocols.LispMapRequest;
40import org.onosproject.lisp.msg.protocols.LispMapRequest.RequestBuilder;
Jian Li451cea32016-10-04 15:27:50 +090041import org.onosproject.lisp.msg.protocols.LispMessage;
Jian Li6ef1b3f2016-11-12 18:16:06 +090042import org.onosproject.lisp.msg.types.LispAfiAddress;
43import org.onosproject.lisp.msg.types.LispIpv4Address;
44import org.onosproject.lisp.msg.types.LispIpv6Address;
Jian Lif31019a2017-02-05 07:57:46 +090045import org.onosproject.lisp.msg.types.lcaf.LispNatLcafAddress.NatAddressBuilder;
Jian Li6ef1b3f2016-11-12 18:16:06 +090046import org.onosproject.lisp.msg.types.LispNoAddress;
Jian Li24f6cc02016-11-01 16:38:40 +090047import org.slf4j.Logger;
48import org.slf4j.LoggerFactory;
49
Jian Li6ef1b3f2016-11-12 18:16:06 +090050import java.net.InetAddress;
Jian Li24f6cc02016-11-01 16:38:40 +090051import java.net.InetSocketAddress;
Jian Li6ef1b3f2016-11-12 18:16:06 +090052import java.net.UnknownHostException;
Jian Li24f6cc02016-11-01 16:38:40 +090053import java.util.Arrays;
Jian Lib86d8ad2017-05-03 02:53:44 +090054import java.util.Collection;
55import java.util.List;
Jian Li24f6cc02016-11-01 16:38:40 +090056
Jian Licdbc0872016-12-05 17:23:53 +090057import static org.onlab.packet.IpAddress.valueOf;
Jian Li24f6cc02016-11-01 16:38:40 +090058import static org.onosproject.lisp.msg.authentication.LispAuthenticationKeyEnum.valueOf;
Jian Li451cea32016-10-04 15:27:50 +090059
60/**
61 * LISP map server class.
62 * Handles map-register message and acknowledges with map-notify message.
63 */
Jian Li712ec052016-11-22 03:23:54 +090064public final class LispMapServer {
Jian Li6322a362016-10-31 00:57:19 +090065
Jian Licdbc0872016-12-05 17:23:53 +090066 private static final Logger log = LoggerFactory.getLogger(LispMapServer.class);
67
Jian Lid1a109e2016-11-12 09:00:42 +090068 private static final int MAP_NOTIFY_PORT = 4342;
Jian Li6ef1b3f2016-11-12 18:16:06 +090069 private static final int INFO_REPLY_PORT = 4342;
Jian Li24f6cc02016-11-01 16:38:40 +090070
Jian Licdbc0872016-12-05 17:23:53 +090071 private static final String INVALID_AUTHENTICATION_DATA_MSG =
72 "Unmatched authentication data of {}.";
73 private static final String FAILED_TO_FORMULATE_NAT_MSG =
74 "Fails during formulate NAT address.";
75
Jian Lib86d8ad2017-05-03 02:53:44 +090076 private boolean enableSmr = false;
Jian Li24f6cc02016-11-01 16:38:40 +090077
Jian Li29986d82016-12-01 03:25:12 +090078 private LispMappingDatabase mapDb = LispMappingDatabase.getInstance();
Jian Li712ec052016-11-22 03:23:54 +090079 private LispAuthenticationConfig authConfig = LispAuthenticationConfig.getInstance();
Jian Li24f6cc02016-11-01 16:38:40 +090080
Jian Li712ec052016-11-22 03:23:54 +090081 // non-instantiable (except for our Singleton)
82 private LispMapServer() {
Jian Li24f6cc02016-11-01 16:38:40 +090083 }
84
Jian Licdbc0872016-12-05 17:23:53 +090085 static LispMapServer getInstance() {
Jian Li29986d82016-12-01 03:25:12 +090086 return SingletonHelper.INSTANCE;
87 }
88
Jian Li24f6cc02016-11-01 16:38:40 +090089 /**
Jian Lib86d8ad2017-05-03 02:53:44 +090090 * Enable LISP Map server sends SMR(Solicit Map Request) message.
91 *
92 * @param enable whether enable or disable sending SMR
93 */
94 public void enableSmr(boolean enable) {
95 this.enableSmr = enable;
96 }
97
98 /**
Jian Li24f6cc02016-11-01 16:38:40 +090099 * Handles map-register message and replies with map-notify message.
100 *
101 * @param message map-register message
102 * @return map-notify message
103 */
Jian Licdbc0872016-12-05 17:23:53 +0900104 LispMapNotify processMapRegister(LispMessage message) {
Jian Li24f6cc02016-11-01 16:38:40 +0900105
106 LispMapRegister register = (LispMapRegister) message;
107
Jian Lid1a109e2016-11-12 09:00:42 +0900108 if (!checkMapRegisterAuthData(register)) {
Jian Licdbc0872016-12-05 17:23:53 +0900109 log.warn(INVALID_AUTHENTICATION_DATA_MSG, "Map-Register");
Jian Li24f6cc02016-11-01 16:38:40 +0900110 return null;
111 }
112
Jian Li29986d82016-12-01 03:25:12 +0900113 register.getMapRecords().forEach(mapRecord -> {
114 LispEidRecord eidRecord =
Jian Licdbc0872016-12-05 17:23:53 +0900115 new LispEidRecord(mapRecord.getMaskLength(),
116 mapRecord.getEidPrefixAfi());
Jian Li29986d82016-12-01 03:25:12 +0900117
Jian Lib86d8ad2017-05-03 02:53:44 +0900118 LispMapRecord oldMapRecord = mapDb.getMapRecordByEidRecord(eidRecord,
119 register.isProxyMapReply());
120 if (oldMapRecord == null) {
121 mapDb.putMapRecord(eidRecord, mapRecord, register.isProxyMapReply());
122 } else {
123 if (oldMapRecord.getMapVersionNumber() <= mapRecord.getMapVersionNumber()) {
124 mapDb.putMapRecord(eidRecord, mapRecord, register.isProxyMapReply());
125
126 if (enableSmr) {
127 sendSmrMessage(eidRecord);
128 }
129 }
130 }
Jian Li29986d82016-12-01 03:25:12 +0900131 });
132
Jian Li2c8a2a42016-11-24 02:51:03 +0900133 // we only acknowledge back to ETR when want-map-notify bit is set to true
134 // otherwise, we do not acknowledge back to ETR
135 if (register.isWantMapNotify()) {
136 NotifyBuilder notifyBuilder = new DefaultNotifyBuilder();
137 notifyBuilder.withKeyId(authConfig.lispAuthKeyId());
138 notifyBuilder.withAuthDataLength(valueOf(authConfig.lispAuthKeyId()).getHashLength());
139 notifyBuilder.withAuthKey(authConfig.lispAuthKey());
140 notifyBuilder.withNonce(register.getNonce());
141 notifyBuilder.withMapRecords(register.getMapRecords());
Jian Li24f6cc02016-11-01 16:38:40 +0900142
Jian Li2c8a2a42016-11-24 02:51:03 +0900143 LispMapNotify notify = notifyBuilder.build();
Jian Li24f6cc02016-11-01 16:38:40 +0900144
Jian Li2c8a2a42016-11-24 02:51:03 +0900145 InetSocketAddress address =
146 new InetSocketAddress(register.getSender().getAddress(), MAP_NOTIFY_PORT);
147 notify.configSender(address);
Jian Li24f6cc02016-11-01 16:38:40 +0900148
Jian Li2c8a2a42016-11-24 02:51:03 +0900149 return notify;
150 }
151
152 return null;
Jian Li24f6cc02016-11-01 16:38:40 +0900153 }
154
155 /**
Jian Li6ef1b3f2016-11-12 18:16:06 +0900156 * Handles info-request message and replies with info-reply message.
157 *
158 * @param message info-request message
159 * @return info-reply message
160 */
Jian Licdbc0872016-12-05 17:23:53 +0900161 LispInfoReply processInfoRequest(LispMessage message) {
Jian Li6ef1b3f2016-11-12 18:16:06 +0900162 LispInfoRequest request = (LispInfoRequest) message;
163
164 if (!checkInfoRequestAuthData(request)) {
Jian Licdbc0872016-12-05 17:23:53 +0900165 log.warn(INVALID_AUTHENTICATION_DATA_MSG, "Info-Request");
Jian Li6ef1b3f2016-11-12 18:16:06 +0900166 return null;
167 }
168
169 NatAddressBuilder natBuilder = new NatAddressBuilder();
170 try {
171 LispAfiAddress msAddress =
Jian Licdbc0872016-12-05 17:23:53 +0900172 new LispIpv4Address(valueOf(InetAddress.getLocalHost()));
Jian Li6ef1b3f2016-11-12 18:16:06 +0900173 natBuilder.withMsRlocAddress(msAddress);
174 natBuilder.withMsUdpPortNumber((short) INFO_REPLY_PORT);
175
176 // try to extract global ETR RLOC address from info-request
Jian Licdbc0872016-12-05 17:23:53 +0900177 IpAddress globalRlocIp = valueOf(request.getSender().getAddress());
Jian Li6ef1b3f2016-11-12 18:16:06 +0900178 LispAfiAddress globalRlocAddress;
179 if (globalRlocIp.isIp4()) {
180 globalRlocAddress = new LispIpv4Address(globalRlocIp);
181 } else {
182 globalRlocAddress = new LispIpv6Address(globalRlocIp);
183 }
184 natBuilder.withGlobalEtrRlocAddress(globalRlocAddress);
185 natBuilder.withEtrUdpPortNumber((short) request.getSender().getPort());
186 natBuilder.withPrivateEtrRlocAddress(new LispNoAddress());
187
188 // TODO: need to specify RTR addresses
189
190 } catch (UnknownHostException e) {
Jian Licdbc0872016-12-05 17:23:53 +0900191 log.warn(FAILED_TO_FORMULATE_NAT_MSG, e);
Jian Li6ef1b3f2016-11-12 18:16:06 +0900192 }
193
Jian Li5e505c62016-12-05 02:44:24 +0900194 InfoReplyBuilder replyBuilder = new DefaultInfoReplyBuilder();
Jian Li6ef1b3f2016-11-12 18:16:06 +0900195 replyBuilder.withKeyId(request.getKeyId());
Jian Li712ec052016-11-22 03:23:54 +0900196 replyBuilder.withAuthDataLength(valueOf(authConfig.lispAuthKeyId()).getHashLength());
197 replyBuilder.withAuthKey(authConfig.lispAuthKey());
Jian Li6ef1b3f2016-11-12 18:16:06 +0900198 replyBuilder.withNonce(request.getNonce());
199 replyBuilder.withEidPrefix(request.getPrefix());
200 replyBuilder.withMaskLength(request.getMaskLength());
201 replyBuilder.withTtl(request.getTtl());
202 replyBuilder.withNatLcafAddress(natBuilder.build());
203 replyBuilder.withIsInfoReply(true);
204
205 LispInfoReply reply = replyBuilder.build();
206 reply.configSender(request.getSender());
207
208 return reply;
209 }
210
211 /**
Jian Li51aaca12016-11-11 01:56:15 +0900212 * Checks the integrity of the received map-register message by calculating
213 * authentication data from received map-register message.
Jian Li24f6cc02016-11-01 16:38:40 +0900214 *
Jian Li51aaca12016-11-11 01:56:15 +0900215 * @param register map-register message
Jian Li24f6cc02016-11-01 16:38:40 +0900216 * @return evaluation result
217 */
Jian Lid1a109e2016-11-12 09:00:42 +0900218 private boolean checkMapRegisterAuthData(LispMapRegister register) {
Jian Li24f6cc02016-11-01 16:38:40 +0900219 RegisterBuilder registerBuilder = new DefaultRegisterBuilder();
220 registerBuilder.withKeyId(register.getKeyId());
Jian Li712ec052016-11-22 03:23:54 +0900221 registerBuilder.withAuthKey(authConfig.lispAuthKey());
Jian Li24f6cc02016-11-01 16:38:40 +0900222 registerBuilder.withNonce(register.getNonce());
223 registerBuilder.withIsProxyMapReply(register.isProxyMapReply());
224 registerBuilder.withIsWantMapNotify(register.isWantMapNotify());
225 registerBuilder.withMapRecords(register.getMapRecords());
Jian Li6ef1b3f2016-11-12 18:16:06 +0900226
Jian Lid1a109e2016-11-12 09:00:42 +0900227 LispMapRegister authRegister = registerBuilder.build();
Jian Li24f6cc02016-11-01 16:38:40 +0900228
Jian Lid1a109e2016-11-12 09:00:42 +0900229 return Arrays.equals(authRegister.getAuthData(), register.getAuthData());
Jian Li451cea32016-10-04 15:27:50 +0900230 }
Jian Li6ef1b3f2016-11-12 18:16:06 +0900231
232 /**
233 * Checks the integrity of the received info-request message by calculating
234 * authentication data from received info-request message.
235 *
236 * @param request info-request message
237 * @return evaluation result
238 */
239 private boolean checkInfoRequestAuthData(LispInfoRequest request) {
240 InfoRequestBuilder requestBuilder = new DefaultInfoRequestBuilder();
241 requestBuilder.withKeyId(request.getKeyId());
Jian Li712ec052016-11-22 03:23:54 +0900242 requestBuilder.withAuthKey(authConfig.lispAuthKey());
Jian Li6ef1b3f2016-11-12 18:16:06 +0900243 requestBuilder.withNonce(request.getNonce());
244 requestBuilder.withTtl(request.getTtl());
245 requestBuilder.withEidPrefix(request.getPrefix());
246 requestBuilder.withIsInfoReply(request.isInfoReply());
247 requestBuilder.withMaskLength(request.getMaskLength());
248
yoonseon980cd7c2016-11-18 14:18:46 -0800249 LispInfoRequest authRequest = requestBuilder.build();
Jian Li6ef1b3f2016-11-12 18:16:06 +0900250
251 return Arrays.equals(authRequest.getAuthData(), request.getAuthData());
252 }
Jian Li712ec052016-11-22 03:23:54 +0900253
254 /**
Jian Lib86d8ad2017-05-03 02:53:44 +0900255 * Sends SMR (Solicit Map Request) to their subscribers.
256 *
257 * @param eidRecord the updated EID
258 */
259 private void sendSmrMessage(LispEidRecord eidRecord) {
260
261 RequestBuilder builder = new DefaultRequestBuilder();
262
263 LispAfiAddress msAddress = null;
264 try {
265 msAddress = new LispIpv4Address(IpAddress.valueOf(InetAddress.getLocalHost()));
266 } catch (UnknownHostException e) {
267 log.warn("Source EID is not found, {}", e.getMessage());
268 }
269
270 LispMapRequest msg = builder.withIsSmr(true)
271 .withIsSmrInvoked(true)
272 .withIsProbe(false)
273 .withIsPitr(false)
274 .withIsAuthoritative(false)
275 .withIsMapDataPresent(false)
276 .withSourceEid(msAddress)
277 .withEidRecords(ImmutableList.of(eidRecord))
278 .build();
279
280 LispRouterFactory routerFactory = LispRouterFactory.getInstance();
281 Collection<LispRouter> routers = routerFactory.getRouters();
282 routers.forEach(router -> {
283 if (isInEidRecordRange(eidRecord, router.getEidRecords())) {
284 router.sendMessage(msg);
285 }
286 });
287 }
288
289 private boolean isInEidRecordRange(LispEidRecord originalRecord, List<LispEidRecord> records) {
290
291 for (LispEidRecord record : records) {
292 return LispMapUtil.isInRange(record, originalRecord) ||
293 LispMapUtil.isInRange(originalRecord, record);
294 }
295 return false;
296 }
297
298 /**
Jian Li712ec052016-11-22 03:23:54 +0900299 * Prevents object instantiation from external.
300 */
Jian Li29986d82016-12-01 03:25:12 +0900301 private static final class SingletonHelper {
302 private static final String ILLEGAL_ACCESS_MSG = "Should not instantiate this class.";
Jian Li712ec052016-11-22 03:23:54 +0900303 private static final LispMapServer INSTANCE = new LispMapServer();
Jian Li29986d82016-12-01 03:25:12 +0900304
305 private SingletonHelper() {
306 throw new IllegalAccessError(ILLEGAL_ACCESS_MSG);
307 }
Jian Li712ec052016-11-22 03:23:54 +0900308 }
Jian Li451cea32016-10-04 15:27:50 +0900309}