Hyunsun Moon
Committed by Gerrit Code Review

Improved openstackSwitching ARP handler

Save REST calls by checking if the target IP is owned by a known host first.

Change-Id: Id1ac0e5e13d635b5216d50c7cafaed1179a7410e
...@@ -18,12 +18,14 @@ package org.onosproject.openstackswitching; ...@@ -18,12 +18,14 @@ package org.onosproject.openstackswitching;
18 import org.onlab.packet.ARP; 18 import org.onlab.packet.ARP;
19 import org.onlab.packet.Ethernet; 19 import org.onlab.packet.Ethernet;
20 import org.onlab.packet.Ip4Address; 20 import org.onlab.packet.Ip4Address;
21 +import org.onlab.packet.IpAddress;
21 import org.onlab.packet.MacAddress; 22 import org.onlab.packet.MacAddress;
23 +import org.onosproject.net.Host;
22 import org.onosproject.net.flow.DefaultTrafficTreatment; 24 import org.onosproject.net.flow.DefaultTrafficTreatment;
23 import org.onosproject.net.flow.TrafficTreatment; 25 import org.onosproject.net.flow.TrafficTreatment;
26 +import org.onosproject.net.host.HostService;
24 import org.onosproject.net.packet.DefaultOutboundPacket; 27 import org.onosproject.net.packet.DefaultOutboundPacket;
25 import org.onosproject.net.packet.InboundPacket; 28 import org.onosproject.net.packet.InboundPacket;
26 -import org.onosproject.net.packet.OutboundPacket;
27 import org.onosproject.net.packet.PacketService; 29 import org.onosproject.net.packet.PacketService;
28 import org.slf4j.Logger; 30 import org.slf4j.Logger;
29 import org.slf4j.LoggerFactory; 31 import org.slf4j.LoggerFactory;
...@@ -40,69 +42,106 @@ public class OpenstackArpHandler { ...@@ -40,69 +42,106 @@ public class OpenstackArpHandler {
40 .getLogger(OpenstackArpHandler.class); 42 .getLogger(OpenstackArpHandler.class);
41 private PacketService packetService; 43 private PacketService packetService;
42 private OpenstackRestHandler restHandler; 44 private OpenstackRestHandler restHandler;
45 + private HostService hostService;
43 46
44 /** 47 /**
45 * Returns OpenstackArpHandler reference. 48 * Returns OpenstackArpHandler reference.
46 * 49 *
47 * @param restHandler rest API handler reference 50 * @param restHandler rest API handler reference
48 * @param packetService PacketService reference 51 * @param packetService PacketService reference
52 + * @param hostService host service
49 */ 53 */
50 - public OpenstackArpHandler(OpenstackRestHandler restHandler, PacketService packetService) { 54 + public OpenstackArpHandler(OpenstackRestHandler restHandler, PacketService packetService,
55 + HostService hostService) {
51 this.restHandler = checkNotNull(restHandler); 56 this.restHandler = checkNotNull(restHandler);
52 this.packetService = packetService; 57 this.packetService = packetService;
58 + this.hostService = hostService;
53 } 59 }
54 60
55 /** 61 /**
56 - * Processes ARP packets. 62 + * Processes ARP request packets.
63 + * It checks if the target IP is owned by a known host first and then ask to
64 + * OpenStack if it's not. This ARP proxy does not support overlapping IP.
57 * 65 *
58 * @param pkt ARP request packet 66 * @param pkt ARP request packet
59 */ 67 */
60 public void processPacketIn(InboundPacket pkt) { 68 public void processPacketIn(InboundPacket pkt) {
61 - Ethernet ethernet = pkt.parsed(); 69 + Ethernet ethRequest = pkt.parsed();
62 - ARP arp = (ARP) ethernet.getPayload(); 70 + ARP arp = (ARP) ethRequest.getPayload();
63 - 71 +
64 - if (arp.getOpCode() == ARP.OP_REQUEST) { 72 + if (arp.getOpCode() != ARP.OP_REQUEST) {
65 - byte[] srcMacAddress = arp.getSenderHardwareAddress(); 73 + return;
66 - byte[] srcIPAddress = arp.getSenderProtocolAddress(); 74 + }
67 - byte[] dstIPAddress = arp.getTargetProtocolAddress(); 75 +
68 - 76 + IpAddress targetIp = Ip4Address.valueOf(arp.getTargetProtocolAddress());
69 - //Searches the Dst MAC Address based on openstackPortMap 77 + MacAddress dstMac = getMacFromHostService(targetIp);
70 - MacAddress macAddress = null; 78 + if (dstMac == null) {
71 - 79 + dstMac = getMacFromOpenstack(targetIp);
72 - OpenstackPort openstackPort = restHandler.getPorts().stream(). 80 + }
73 - filter(e -> e.fixedIps().containsValue(Ip4Address.valueOf( 81 +
74 - dstIPAddress))).findAny().orElse(null); 82 + if (dstMac == null) {
75 - 83 + log.debug("Failed to find MAC address for {}", targetIp.toString());
76 - if (openstackPort != null) { 84 + return;
77 - macAddress = openstackPort.macAddress(); 85 + }
78 - log.debug("Found MACAddress: {}", macAddress.toString()); 86 +
79 - } else { 87 + Ethernet ethReply = ARP.buildArpReply(targetIp.getIp4Address(),
80 - return; 88 + dstMac,
81 - } 89 + ethRequest);
82 - 90 +
83 - //Creates a response packet 91 + TrafficTreatment treatment = DefaultTrafficTreatment.builder()
84 - ARP arpReply = new ARP(); 92 + .setOutput(pkt.receivedFrom().port())
85 - arpReply.setOpCode(ARP.OP_REPLY) 93 + .build();
86 - .setHardwareAddressLength(arp.getHardwareAddressLength()) 94 +
87 - .setHardwareType(arp.getHardwareType()) 95 + packetService.emit(new DefaultOutboundPacket(
88 - .setProtocolAddressLength(arp.getProtocolAddressLength()) 96 + pkt.receivedFrom().deviceId(),
89 - .setProtocolType(arp.getProtocolType()) 97 + treatment,
90 - .setSenderHardwareAddress(macAddress.toBytes()) 98 + ByteBuffer.wrap(ethReply.serialize())));
91 - .setSenderProtocolAddress(dstIPAddress) 99 + }
92 - .setTargetHardwareAddress(srcMacAddress) 100 +
93 - .setTargetProtocolAddress(srcIPAddress); 101 + /**
94 - 102 + * Returns MAC address of a host with a given target IP address by asking to
95 - //Sends a response packet 103 + * OpenStack. It does not support overlapping IP.
96 - ethernet.setDestinationMACAddress(srcMacAddress) 104 + *
97 - .setSourceMACAddress(macAddress) 105 + * @param targetIp target ip address
98 - .setEtherType(Ethernet.TYPE_ARP) 106 + * @return mac address, or null if it fails to fetch the mac
99 - .setPayload(arpReply); 107 + */
100 - 108 + private MacAddress getMacFromOpenstack(IpAddress targetIp) {
101 - TrafficTreatment.Builder builder = DefaultTrafficTreatment.builder(); 109 + checkNotNull(targetIp);
102 - builder.setOutput(pkt.receivedFrom().port()); 110 +
103 - OutboundPacket packet = new DefaultOutboundPacket(pkt.receivedFrom().deviceId(), 111 + OpenstackPort openstackPort = restHandler.getPorts()
104 - builder.build(), ByteBuffer.wrap(ethernet.serialize())); 112 + .stream()
105 - packetService.emit(packet); 113 + .filter(port -> port.fixedIps().containsValue(targetIp))
114 + .findFirst()
115 + .orElse(null);
116 +
117 + if (openstackPort != null) {
118 + log.debug("Found MAC from OpenStack for {}", targetIp.toString());
119 + return openstackPort.macAddress();
120 + } else {
121 + return null;
122 + }
123 + }
124 +
125 + /**
126 + * Returns MAC address of a host with a given target IP address by asking to
127 + * host service. It does not support overlapping IP.
128 + *
129 + * @param targetIp target ip
130 + * @return mac address, or null if it fails to find the mac
131 + */
132 + private MacAddress getMacFromHostService(IpAddress targetIp) {
133 + checkNotNull(targetIp);
134 +
135 + Host host = hostService.getHostsByIp(targetIp)
136 + .stream()
137 + .findFirst()
138 + .orElse(null);
139 +
140 + if (host != null) {
141 + log.debug("Found MAC from host service for {}", targetIp.toString());
142 + return host.mac();
143 + } else {
144 + return null;
106 } 145 }
107 } 146 }
108 } 147 }
......
...@@ -394,7 +394,7 @@ public class OpenstackSwitchingManager implements OpenstackSwitchingService { ...@@ -394,7 +394,7 @@ public class OpenstackSwitchingManager implements OpenstackSwitchingService {
394 InboundPacket pkt = context.inPacket(); 394 InboundPacket pkt = context.inPacket();
395 Ethernet ethernet = pkt.parsed(); 395 Ethernet ethernet = pkt.parsed();
396 396
397 - if (ethernet.getEtherType() == Ethernet.TYPE_ARP) { 397 + if (ethernet != null && ethernet.getEtherType() == Ethernet.TYPE_ARP) {
398 arpHandler.processPacketIn(pkt); 398 arpHandler.processPacketIn(pkt);
399 } 399 }
400 } 400 }
...@@ -483,7 +483,7 @@ public class OpenstackSwitchingManager implements OpenstackSwitchingService { ...@@ -483,7 +483,7 @@ public class OpenstackSwitchingManager implements OpenstackSwitchingService {
483 } 483 }
484 doNotPushFlows = cfg.doNotPushFlows(); 484 doNotPushFlows = cfg.doNotPushFlows();
485 restHandler = new OpenstackRestHandler(cfg); 485 restHandler = new OpenstackRestHandler(cfg);
486 - arpHandler = new OpenstackArpHandler(restHandler, packetService); 486 + arpHandler = new OpenstackArpHandler(restHandler, packetService, hostService);
487 initializeFlowRules(); 487 initializeFlowRules();
488 } 488 }
489 489
......