blob: c7fc41773f6b9df8706cdf65511f91fd557b20f5 [file] [log] [blame]
Jian Li63430202018-08-30 16:24:09 +09001/*
2 * Copyright 2018-present Open Networking Foundation
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
17package org.onosproject.openstacknetworking.impl;
18
Jian Li46650932018-09-04 23:52:11 +090019import com.google.common.collect.ImmutableSet;
Jian Li63430202018-08-30 16:24:09 +090020import org.apache.commons.lang.StringUtils;
21import org.apache.felix.scr.annotations.Activate;
22import org.apache.felix.scr.annotations.Component;
23import org.apache.felix.scr.annotations.Deactivate;
Jian Li63430202018-08-30 16:24:09 +090024import org.apache.felix.scr.annotations.Reference;
25import org.apache.felix.scr.annotations.ReferenceCardinality;
26import org.apache.http.Header;
27import org.apache.http.HttpEntityEnclosingRequest;
28import org.apache.http.HttpMessage;
29import org.apache.http.HttpRequest;
30import org.apache.http.HttpResponse;
31import org.apache.http.client.methods.CloseableHttpResponse;
Jian Li46650932018-09-04 23:52:11 +090032import org.apache.http.client.methods.HttpDelete;
Jian Li63430202018-08-30 16:24:09 +090033import org.apache.http.client.methods.HttpGet;
34import org.apache.http.client.methods.HttpPost;
Jian Li46650932018-09-04 23:52:11 +090035import org.apache.http.client.methods.HttpPut;
Jian Li63430202018-08-30 16:24:09 +090036import org.apache.http.client.methods.HttpRequestBase;
37import org.apache.http.impl.client.CloseableHttpClient;
38import org.apache.http.impl.client.HttpClientBuilder;
39import org.apache.http.message.BasicHeader;
40import org.apache.http.message.BasicHttpResponse;
41import org.onlab.packet.BasePacket;
42import org.onlab.packet.Data;
43import org.onlab.packet.Ethernet;
44import org.onlab.packet.IPv4;
45import org.onlab.packet.IpAddress;
46import org.onlab.packet.IpPrefix;
47import org.onlab.packet.TCP;
48import org.onlab.packet.TpPort;
Jian Li63430202018-08-30 16:24:09 +090049import org.onosproject.cluster.ClusterService;
50import org.onosproject.cluster.LeadershipService;
51import org.onosproject.cluster.NodeId;
52import org.onosproject.core.ApplicationId;
53import org.onosproject.core.CoreService;
54import org.onosproject.net.ConnectPoint;
55import org.onosproject.net.flow.DefaultTrafficSelector;
56import org.onosproject.net.flow.DefaultTrafficTreatment;
57import org.onosproject.net.flow.TrafficSelector;
58import org.onosproject.net.flow.TrafficTreatment;
59import org.onosproject.net.packet.DefaultOutboundPacket;
60import org.onosproject.net.packet.PacketContext;
61import org.onosproject.net.packet.PacketProcessor;
62import org.onosproject.net.packet.PacketService;
63import org.onosproject.openstacknetworking.api.Constants;
64import org.onosproject.openstacknetworking.api.InstancePort;
65import org.onosproject.openstacknetworking.api.InstancePortService;
66import org.onosproject.openstacknetworking.api.OpenstackFlowRuleService;
67import org.onosproject.openstacknetworking.api.OpenstackNetworkService;
68import org.onosproject.openstacknode.api.OpenstackNode;
69import org.onosproject.openstacknode.api.OpenstackNodeEvent;
70import org.onosproject.openstacknode.api.OpenstackNodeListener;
71import org.onosproject.openstacknode.api.OpenstackNodeService;
72import org.openstack4j.model.network.Port;
Jian Li63430202018-08-30 16:24:09 +090073import org.slf4j.Logger;
74
75import java.io.IOException;
76import java.nio.ByteBuffer;
Jian Li63430202018-08-30 16:24:09 +090077import java.util.Objects;
Jian Li46650932018-09-04 23:52:11 +090078import java.util.Set;
Jian Li63430202018-08-30 16:24:09 +090079
80import static org.onosproject.openstacknetworking.api.Constants.DHCP_ARP_TABLE;
81import static org.onosproject.openstacknetworking.api.Constants.PRIORITY_DHCP_RULE;
82import static org.onosproject.openstacknetworking.impl.OpenstackMetadataProxyHandler.Http.Type.RESPONSE;
83import static org.onosproject.openstacknetworking.util.OpenstackNetworkingUtil.hmacEncrypt;
84import static org.onosproject.openstacknetworking.util.OpenstackNetworkingUtil.parseHttpRequest;
85import static org.onosproject.openstacknetworking.util.OpenstackNetworkingUtil.unparseHttpResponseBody;
86import static org.onosproject.openstacknetworking.util.OpenstackNetworkingUtil.unparseHttpResponseHeader;
87import static org.onosproject.openstacknode.api.OpenstackNode.NodeType.COMPUTE;
88import static org.onosproject.openstacknode.api.OpenstackNode.NodeType.CONTROLLER;
89import static org.slf4j.LoggerFactory.getLogger;
90
91/**
92 * Handles metadata requests for the virtual instances.
93 */
94@Component(immediate = true)
95public class OpenstackMetadataProxyHandler {
96 protected final Logger log = getLogger(getClass());
97
98 private static final String METADATA_SERVER_IP = "169.254.169.254";
99 private static final int METADATA_SERVER_PORT = 8775;
100 private static final int HTTP_SERVER_PORT = 80;
101 private static final int PREFIX_LENGTH = 32;
102 private static final short WINDOW_SIZE = (short) 0x1000;
103 private static final short FIN_FLAG = (short) 0x01;
104 private static final short SYN_FLAG = (short) 0x02;
105 private static final short ACK_FLAG = (short) 0x10;
106 private static final short SYN_ACK_FLAG = (short) 0x12;
107 private static final short FIN_ACK_FLAG = (short) 0x11;
108 private static final byte DATA_OFFSET = (byte) 0x5;
109 private static final short URGENT_POINTER = (short) 0x1;
110 private static final byte PACKET_TTL = (byte) 127;
111 private static final String HTTP_PREFIX = "http://";
112 private static final String COLON = ":";
113
114 private static final String INSTANCE_ID_HEADER = "X-Instance-ID";
115 private static final String INSTANCE_ID_SIGNATURE_HEADER = "X-Instance-ID-Signature";
116 private static final String TENANT_ID_HEADER = "X-Tenant-ID";
117 private static final String FORWARDED_FOR_HEADER = "X-Forwarded-For";
118
119 private static final String HTTP_GET_METHOD = "GET";
120 private static final String HTTP_POST_METHOD = "POST";
Jian Li46650932018-09-04 23:52:11 +0900121 private static final String HTTP_PUT_METHOD = "PUT";
122 private static final String HTTP_DELETE_METHOD = "DELETE";
Jian Li63430202018-08-30 16:24:09 +0900123
124 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
125 protected CoreService coreService;
126
127 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Jian Li63430202018-08-30 16:24:09 +0900128 protected PacketService packetService;
129
130 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
131 protected ClusterService clusterService;
132
133 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
134 protected LeadershipService leadershipService;
135
136 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
137 protected OpenstackNetworkService osNetworkService;
138
139 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
140 protected OpenstackNodeService osNodeService;
141
142 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
143 protected InstancePortService instancePortService;
144
145 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
146 protected OpenstackFlowRuleService osFlowRuleService;
147
Jian Li63430202018-08-30 16:24:09 +0900148 private final PacketProcessor packetProcessor = new InternalPacketProcessor();
149 private final OpenstackNodeListener osNodeListener = new InternalNodeEventListener();
150
Jian Li46650932018-09-04 23:52:11 +0900151 private Set<String> excludedHeaders = ImmutableSet.of("content-type", "content-length");
152
Jian Li63430202018-08-30 16:24:09 +0900153 private ApplicationId appId;
154 private NodeId localNodeId;
155
156 @Activate
157 protected void activate() {
158 appId = coreService.registerApplication(Constants.OPENSTACK_NETWORKING_APP_ID);
159 localNodeId = clusterService.getLocalNode().id();
Jian Li63430202018-08-30 16:24:09 +0900160 osNodeService.addListener(osNodeListener);
161 packetService.addProcessor(packetProcessor, PacketProcessor.director(0));
162 leadershipService.runForLeadership(appId.name());
163
164 log.info("Started");
165 }
166
167 @Deactivate
168 protected void deactivate() {
169 packetService.removeProcessor(packetProcessor);
Jian Li63430202018-08-30 16:24:09 +0900170 osNodeService.removeListener(osNodeListener);
171 leadershipService.withdraw(appId.name());
172
173 log.info("Stopped");
174 }
175
Jian Li63430202018-08-30 16:24:09 +0900176 private class InternalPacketProcessor implements PacketProcessor {
177
178 @Override
179 public void process(PacketContext context) {
Jian Li46650932018-09-04 23:52:11 +0900180
181 if (!useMetadataProxy()) {
182 return;
183 }
184
Jian Li63430202018-08-30 16:24:09 +0900185 if (context.isHandled()) {
186 return;
187 }
188
189 Ethernet ethPacket = context.inPacket().parsed();
190 if (ethPacket == null || ethPacket.getEtherType() != Ethernet.TYPE_IPV4) {
191 return;
192 }
193
194 IPv4 ipv4Packet = (IPv4) ethPacket.getPayload();
195 if (ipv4Packet.getProtocol() != IPv4.PROTOCOL_TCP ||
196 !IpAddress.valueOf(ipv4Packet.getDestinationAddress()).
197 equals(IpAddress.valueOf(METADATA_SERVER_IP))) {
198 return;
199 }
200
201 TCP tcpPacket = (TCP) ipv4Packet.getPayload();
202 if (tcpPacket.getDestinationPort() != HTTP_SERVER_PORT) {
203 return;
204 }
205
Jian Li46650932018-09-04 23:52:11 +0900206 // (three-way handshaking)
207 // reply TCP SYN-ACK packet with receiving TCP SYN packet
Jian Li63430202018-08-30 16:24:09 +0900208 if (tcpPacket.getFlags() == SYN_FLAG) {
209 Ethernet ethReply = buildTcpSynAckPacket(ethPacket, ipv4Packet, tcpPacket);
210 sendReply(context, ethReply);
211 return;
212 }
213
Jian Li46650932018-09-04 23:52:11 +0900214 // (four-way handshaking)
215 // reply TCP ACK and TCP FIN-ACK packets with receiving TCP FIN-ACK packet
Jian Li63430202018-08-30 16:24:09 +0900216 if (tcpPacket.getFlags() == FIN_ACK_FLAG) {
217 Ethernet ackReply = buildTcpAckPacket(ethPacket, ipv4Packet, tcpPacket);
218 sendReply(context, ackReply);
219 Ethernet finAckReply = buildTcpFinAckPacket(ethPacket, ipv4Packet, tcpPacket);
220 sendReply(context, finAckReply);
221 return;
222 }
223
Jian Li46650932018-09-04 23:52:11 +0900224 // normal TCP data transmission
Jian Li63430202018-08-30 16:24:09 +0900225 Data data = (Data) tcpPacket.getPayload();
226 byte[] byteData = data.getData();
227
228 if (byteData.length != 0) {
229 HttpRequest request = parseHttpRequest(byteData);
230 ConnectPoint cp = context.inPacket().receivedFrom();
231 InstancePort instPort = instancePortService.instancePort(cp.deviceId(), cp.port());
232
233 if (instPort == null || request == null) {
234 log.warn("Cannot send metadata request due to lack of information");
235 return;
236 }
237
238 // attempt to send HTTP request to the meta-data server (nova-api),
Jian Li46650932018-09-04 23:52:11 +0900239 // obtain the HTTP response, relay the response to VM through packet-out
Jian Li63430202018-08-30 16:24:09 +0900240 CloseableHttpResponse proxyResponse = proxyHttpRequest(request, instPort);
241
242 if (proxyResponse == null) {
243 log.warn("No response was received from metadata server");
244 return;
245 }
246
247 HttpResponse response = new BasicHttpResponse(proxyResponse.getStatusLine());
248 response.setEntity(proxyResponse.getEntity());
249 response.setHeaders(proxyResponse.getAllHeaders());
250
251 Http httpResponse = new Http();
252 httpResponse.setType(RESPONSE);
253 httpResponse.setMessage(response);
254
255 TCP tcpReply = buildTcpDataPacket(tcpPacket, byteData.length, response);
256 Ethernet ethReply = buildEthFrame(ethPacket, ipv4Packet, tcpReply);
257 sendReply(context, ethReply);
258
259 try {
260 proxyResponse.close();
261 } catch (IOException e) {
262 log.warn("Failed to close the response connection due to {}", e);
263 }
264 }
265 }
266
267 /**
268 * Builds an ethernet frame contains TCP sync-ack packet generated
269 * from the given TCP sync request packet.
270 *
271 * @param ethRequest ethernet request frame
272 * @param ipv4Request IPv4 request
273 * @param tcpRequest TCP request
274 * @return an ethernet frame contains newly generated TCP reply
275 */
276 private Ethernet buildTcpSynAckPacket(Ethernet ethRequest,
277 IPv4 ipv4Request, TCP tcpRequest) {
278
279 TCP tcpReply = buildTcpSignalPacket(tcpRequest, tcpRequest.getSequence(),
280 tcpRequest.getSequence() + 1, SYN_ACK_FLAG);
281
282 return buildEthFrame(ethRequest, ipv4Request, tcpReply);
283 }
284
285 /**
286 * Builds a TCP ACK packet receiving SYN packet.
287 *
288 * @param ethRequest ethernet request frame
289 * @param ipv4Request IPv4 request
290 * @param tcpRequest TCP request
291 * @return an ethernet frame contains newly generated TCP reply
292 */
293 private Ethernet buildTcpAckPacket(Ethernet ethRequest,
294 IPv4 ipv4Request, TCP tcpRequest) {
295 TCP tcpReply = buildTcpSignalPacket(tcpRequest, tcpRequest.getAcknowledge(),
296 tcpRequest.getSequence() + 1, ACK_FLAG);
297
298 return buildEthFrame(ethRequest, ipv4Request, tcpReply);
299 }
300
301 /**
302 * Builds a TCP FIN-ACK packet receiving FIN-ACK packet.
303 *
304 * @param ethRequest ethernet request frame
305 * @param ipv4Request IPv4 request
306 * @param tcpRequest TCP request
307 * @return an ethernet frame contains newly generated TCP reply
308 */
309 private Ethernet buildTcpFinAckPacket(Ethernet ethRequest,
310 IPv4 ipv4Request, TCP tcpRequest) {
311 TCP tcpReply = buildTcpSignalPacket(tcpRequest, tcpRequest.getAcknowledge(),
312 tcpRequest.getSequence() + 1, FIN_ACK_FLAG);
313
314 return buildEthFrame(ethRequest, ipv4Request, tcpReply);
315 }
316
317 /**
318 * Builds a TCP signaling packet.
319 *
320 * @param tcpRequest TCP request
321 * @param seq sequence number
322 * @param ack ack number
323 * @param flags TCP flags
324 * @return TCP signal packet
325 */
326 private TCP buildTcpSignalPacket(TCP tcpRequest, int seq, int ack, short flags) {
327 TCP tcpReply = new TCP();
328 tcpReply.setSourcePort(tcpRequest.getDestinationPort());
329 tcpReply.setDestinationPort(tcpRequest.getSourcePort());
330 tcpReply.setSequence(seq);
331 tcpReply.setAcknowledge(ack);
332 tcpReply.setDataOffset(DATA_OFFSET);
333 tcpReply.setFlags(flags);
334 tcpReply.setWindowSize(WINDOW_SIZE);
335 tcpReply.setUrgentPointer(URGENT_POINTER);
336
337 return tcpReply;
338 }
339
340 /**
341 * Builds a TCP data packet.
342 *
343 * @param tcpRequest TCP request
344 * @param requestLength TCP request data length
345 * @param response HTTP response
346 * @return a TCP data packet
347 */
348 private TCP buildTcpDataPacket(TCP tcpRequest, int requestLength,
349 HttpResponse response) {
350 TCP tcpReply = new TCP();
351 tcpReply.setSourcePort(tcpRequest.getDestinationPort());
352 tcpReply.setDestinationPort(tcpRequest.getSourcePort());
353 tcpReply.setSequence(tcpRequest.getAcknowledge());
354 tcpReply.setAcknowledge(tcpRequest.getSequence() + requestLength);
355 tcpReply.setDataOffset(DATA_OFFSET); // no options
356 tcpReply.setFlags(ACK_FLAG);
357 tcpReply.setWindowSize(WINDOW_SIZE);
358 tcpReply.setUrgentPointer(URGENT_POINTER);
359
360 Http httpResponse = new Http();
361 httpResponse.setType(RESPONSE);
362 httpResponse.setMessage(response);
363
364 tcpReply.setPayload(httpResponse);
365
366 return tcpReply;
367 }
368
369 /**
370 * Builds an ethernet frame with the given IPv4 and TCP payload.
371 *
372 * @param ethRequest ethernet request frame
373 * @param ipv4Request IPv4 request
374 * @param tcpReply TCP reply
375 * @return an ethernet frame contains TCP payload
376 */
377 private Ethernet buildEthFrame(Ethernet ethRequest, IPv4 ipv4Request,
378 TCP tcpReply) {
379 Ethernet ethReply = new Ethernet();
380 ethReply.setSourceMACAddress(ethRequest.getDestinationMAC());
381 ethReply.setDestinationMACAddress(ethRequest.getSourceMAC());
382 ethReply.setEtherType(ethRequest.getEtherType());
383
384 IPv4 ipv4Reply = new IPv4();
385 ipv4Reply.setSourceAddress(ipv4Request.getDestinationAddress());
386 ipv4Reply.setDestinationAddress(ipv4Request.getSourceAddress());
387 ipv4Reply.setTtl(PACKET_TTL);
388
389 ipv4Reply.setPayload(tcpReply);
390 ethReply.setPayload(ipv4Reply);
391
392 return ethReply;
393 }
394
395 /**
396 * Proxyies HTTP request.
397 *
398 * @param oldRequest HTTP request
399 * @param instPort instance port
400 * @return HTTP response
401 */
402 private CloseableHttpResponse proxyHttpRequest(HttpRequest oldRequest,
403 InstancePort instPort) {
404
405 CloseableHttpClient client = HttpClientBuilder.create().build();
406 OpenstackNode controller = osNodeService.completeNodes(CONTROLLER).
407 stream().findFirst().orElse(null);
408 if (controller == null) {
409 return null;
410 }
411
412 String path = oldRequest.getRequestLine().getUri();
413 String url = HTTP_PREFIX + controller.managementIp().toString() +
414 COLON + METADATA_SERVER_PORT + path;
415
416 if (StringUtils.isEmpty(url)) {
417 log.warn("The metadata endpoint is not configured!");
418 return null;
419 }
420
Jian Li63430202018-08-30 16:24:09 +0900421 HttpRequestBase request;
422
Jian Li46650932018-09-04 23:52:11 +0900423 String method = oldRequest.getRequestLine().getMethod().toUpperCase();
424
425 log.info("Sending HTTP {} request to metadata endpoint {}...", method, url);
426
427 switch (method) {
Jian Li63430202018-08-30 16:24:09 +0900428 case HTTP_GET_METHOD:
429 request = new HttpGet(url);
430 break;
431 case HTTP_POST_METHOD:
432 request = new HttpPost(url);
Jian Li46650932018-09-04 23:52:11 +0900433 HttpEntityEnclosingRequest postRequest =
Jian Li63430202018-08-30 16:24:09 +0900434 (HttpEntityEnclosingRequest) oldRequest;
Jian Li46650932018-09-04 23:52:11 +0900435 ((HttpPost) request).setEntity(postRequest.getEntity());
436 break;
437 case HTTP_PUT_METHOD:
438 request = new HttpPut(url);
439 HttpEntityEnclosingRequest putRequest =
440 (HttpEntityEnclosingRequest) oldRequest;
441 ((HttpPut) request).setEntity(putRequest.getEntity());
442 break;
443 case HTTP_DELETE_METHOD:
444 request = new HttpDelete(url);
Jian Li63430202018-08-30 16:24:09 +0900445 break;
446 default:
447 request = new HttpGet(url);
448 break;
449 }
450
451 // configure headers from original HTTP request
452 for (Header header : oldRequest.getAllHeaders()) {
Jian Li46650932018-09-04 23:52:11 +0900453 if (method.equals(HTTP_POST_METHOD) ||
454 method.equals(HTTP_PUT_METHOD)) {
455 // we DO NOT add duplicated HTTP headers for POST and PUT methods
456 if (excludedHeaders.contains(header.getName().toLowerCase())) {
457 continue;
458 }
459 }
Jian Li63430202018-08-30 16:24:09 +0900460 request.addHeader(header);
461 }
462
463 request.setProtocolVersion(oldRequest.getProtocolVersion());
464
465 Port port = osNetworkService.port(instPort.portId());
466
467 request.addHeader(new BasicHeader(INSTANCE_ID_HEADER, port.getDeviceId()));
Jian Li63430202018-08-30 16:24:09 +0900468 request.addHeader(new BasicHeader(TENANT_ID_HEADER, port.getTenantId()));
Jian Li46650932018-09-04 23:52:11 +0900469 request.addHeader(new BasicHeader(FORWARDED_FOR_HEADER, instPort.ipAddress().toString()));
470 if (metadataSecret() != null) {
471 request.addHeader(new BasicHeader(INSTANCE_ID_SIGNATURE_HEADER,
472 hmacEncrypt(metadataSecret(), port.getDeviceId())));
473 }
Jian Li63430202018-08-30 16:24:09 +0900474
475 try {
476 return client.execute(request);
477 } catch (IOException e) {
478 log.warn("Failed to get response from metadata server due to {}", e);
479 }
480
481 return null;
482 }
483
484 /**
485 * Sends out ethernet frame.
486 *
487 * @param context packet context
488 * @param ethReply ethernet frame
489 */
490 private void sendReply(PacketContext context, Ethernet ethReply) {
491 if (ethReply == null) {
492 return;
493 }
494 ConnectPoint srcPoint = context.inPacket().receivedFrom();
495 TrafficTreatment treatment = DefaultTrafficTreatment
496 .builder()
497 .setOutput(srcPoint.port())
498 .build();
499
500 packetService.emit(new DefaultOutboundPacket(
501 srcPoint.deviceId(),
502 treatment,
503 ByteBuffer.wrap(ethReply.serialize())));
504 context.block();
505 }
506 }
507
508 private class InternalNodeEventListener implements OpenstackNodeListener {
509 @Override
510 public boolean isRelevant(OpenstackNodeEvent event) {
511 // do not allow to proceed without leadership
512 NodeId leader = leadershipService.getLeader(appId.name());
513 return Objects.equals(localNodeId, leader) &&
Jian Li46650932018-09-04 23:52:11 +0900514 event.subject().type() == COMPUTE && useMetadataProxy();
Jian Li63430202018-08-30 16:24:09 +0900515 }
516
517 @Override
518 public void event(OpenstackNodeEvent event) {
519 OpenstackNode osNode = event.subject();
520 switch (event.type()) {
521 case OPENSTACK_NODE_COMPLETE:
522 setMetadataRule(osNode, true);
523 break;
524 case OPENSTACK_NODE_INCOMPLETE:
525 setMetadataRule(osNode, false);
526 break;
527 case OPENSTACK_NODE_CREATED:
528 case OPENSTACK_NODE_UPDATED:
529 case OPENSTACK_NODE_REMOVED:
530 default:
531 break;
532 }
533 }
534
535 /**
536 * Installs metadata rule for receiving all metadata request packets.
537 *
538 * @param osNode openstack node
539 * @param install installation flag
540 */
541 private void setMetadataRule(OpenstackNode osNode, boolean install) {
542 TrafficSelector selector = DefaultTrafficSelector.builder()
543 .matchEthType(Ethernet.TYPE_IPV4)
544 .matchIPProtocol(IPv4.PROTOCOL_TCP)
545 .matchIPDst(IpPrefix.valueOf(
546 IpAddress.valueOf(METADATA_SERVER_IP), PREFIX_LENGTH))
547 .matchTcpDst(TpPort.tpPort(HTTP_SERVER_PORT))
548 .build();
549
550 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
551 .punt()
552 .build();
553
554 osFlowRuleService.setRule(
555 appId,
556 osNode.intgBridge(),
557 selector,
558 treatment,
559 PRIORITY_DHCP_RULE,
560 DHCP_ARP_TABLE,
561 install);
562 }
563 }
564
Jian Li46650932018-09-04 23:52:11 +0900565 private boolean useMetadataProxy() {
566 OpenstackNode gw = osNodeService.completeNodes(CONTROLLER)
567 .stream().findFirst().orElse(null);
568
569 if (gw != null && gw.neutronConfig() != null) {
570 return gw.neutronConfig().useMetadataProxy();
571 }
572
573 return false;
574 }
575
576 private String metadataSecret() {
577 OpenstackNode controller = osNodeService.completeNodes(CONTROLLER)
578 .stream().findFirst().orElse(null);
579
580 if (controller != null && controller.neutronConfig() != null) {
581 return controller.neutronConfig().metadataProxySecret();
582 }
583
584 return null;
585 }
586
Jian Li63430202018-08-30 16:24:09 +0900587 /**
588 * Implements Http packet format.
589 */
590 protected static class Http extends BasePacket {
591
592 public enum Type {
593
594 /**
595 * Signifies that this is a Http REQUEST packet.
596 */
597 REQUEST,
598
599 /**
600 * Signifies that this is a Http RESPONSE packet.
601 */
602 RESPONSE,
603 }
604
605 private Type type;
606 private HttpMessage message;
607
608 /**
609 * Obtains the Http type.
610 *
611 * @return Http type
612 */
613 public Type getType() {
614 return type;
615 }
616
617 /**
618 * Configures the Http type.
619 *
620 * @param type Http type
621 */
622 public void setType(Type type) {
623 this.type = type;
624 }
625
626 /**
627 * Obtains the Http message.
628 *
629 * @return Http message
630 */
631 public HttpMessage getMessage() {
632 return message;
633 }
634
635 /**
636 * Configures the Http message.
637 *
638 * @param message Http message
639 */
640 public void setMessage(HttpMessage message) {
641 this.message = message;
642 }
643
644 @Override
645 public byte[] serialize() {
646 if (type == RESPONSE) {
647
648 byte[] header = unparseHttpResponseHeader((HttpResponse) message);
649 byte[] body = unparseHttpResponseBody((HttpResponse) message);
650
651 if (header == null || body == null) {
652 return new byte[0];
653 }
654
655 final byte[] data = new byte[header.length + body.length];
656 final ByteBuffer bb = ByteBuffer.wrap(data);
657 bb.put(header);
658 bb.put(body);
659
660 return data;
661 }
662 return new byte[0];
663 }
664
665 @Override
666 public boolean equals(Object o) {
667
668 if (this == o) {
669 return true;
670 }
671
672 if (o == null || getClass() != o.getClass()) {
673 return false;
674 }
675
676 if (!super.equals(o)) {
677 return false;
678 }
679
680 Http http = (Http) o;
681 return type == http.type &&
682 com.google.common.base.Objects.equal(message, http.message);
683 }
684
685 @Override
686 public int hashCode() {
687 return Objects.hash(type, message);
688 }
689 }
690}