add an ARP reply emulator for public IP to vBNG
Change-Id: Id142ef278363d39330e1c1f061f33d23e6b5e790
Showing
4 changed files
with
199 additions
and
1 deletions
| ... | @@ -23,6 +23,7 @@ import java.util.List; | ... | @@ -23,6 +23,7 @@ import java.util.List; |
| 23 | 23 | ||
| 24 | import org.onlab.packet.IpAddress; | 24 | import org.onlab.packet.IpAddress; |
| 25 | import org.onlab.packet.IpPrefix; | 25 | import org.onlab.packet.IpPrefix; |
| 26 | +import org.onlab.packet.MacAddress; | ||
| 26 | 27 | ||
| 27 | /** | 28 | /** |
| 28 | * Contains the configuration data for virtual BNG that has been read from a | 29 | * Contains the configuration data for virtual BNG that has been read from a |
| ... | @@ -32,6 +33,7 @@ public final class VbngConfiguration { | ... | @@ -32,6 +33,7 @@ public final class VbngConfiguration { |
| 32 | 33 | ||
| 33 | private final List<IpPrefix> localPublicIpPrefixes; | 34 | private final List<IpPrefix> localPublicIpPrefixes; |
| 34 | private final IpAddress nextHopIpAddress; | 35 | private final IpAddress nextHopIpAddress; |
| 36 | + private final MacAddress publicFacingMac; | ||
| 35 | 37 | ||
| 36 | /** | 38 | /** |
| 37 | * Default constructor. | 39 | * Default constructor. |
| ... | @@ -39,6 +41,7 @@ public final class VbngConfiguration { | ... | @@ -39,6 +41,7 @@ public final class VbngConfiguration { |
| 39 | private VbngConfiguration() { | 41 | private VbngConfiguration() { |
| 40 | localPublicIpPrefixes = null; | 42 | localPublicIpPrefixes = null; |
| 41 | nextHopIpAddress = null; | 43 | nextHopIpAddress = null; |
| 44 | + publicFacingMac = null; | ||
| 42 | } | 45 | } |
| 43 | 46 | ||
| 44 | /** | 47 | /** |
| ... | @@ -46,14 +49,19 @@ public final class VbngConfiguration { | ... | @@ -46,14 +49,19 @@ public final class VbngConfiguration { |
| 46 | * | 49 | * |
| 47 | * @param nextHopIpAddress the IP address of the next hop | 50 | * @param nextHopIpAddress the IP address of the next hop |
| 48 | * @param prefixes the public IP prefix list for local SDN network | 51 | * @param prefixes the public IP prefix list for local SDN network |
| 52 | + * @param publicFacingMac the MAC address configured for all local | ||
| 53 | + * public IP addresses | ||
| 49 | */ | 54 | */ |
| 50 | @JsonCreator | 55 | @JsonCreator |
| 51 | public VbngConfiguration(@JsonProperty("localPublicIpPrefixes") | 56 | public VbngConfiguration(@JsonProperty("localPublicIpPrefixes") |
| 52 | List<IpPrefix> prefixes, | 57 | List<IpPrefix> prefixes, |
| 53 | @JsonProperty("nextHopIpAddress") | 58 | @JsonProperty("nextHopIpAddress") |
| 54 | - IpAddress nextHopIpAddress) { | 59 | + IpAddress nextHopIpAddress, |
| 60 | + @JsonProperty("publicFacingMac") | ||
| 61 | + MacAddress publicFacingMac) { | ||
| 55 | localPublicIpPrefixes = prefixes; | 62 | localPublicIpPrefixes = prefixes; |
| 56 | this.nextHopIpAddress = nextHopIpAddress; | 63 | this.nextHopIpAddress = nextHopIpAddress; |
| 64 | + this.publicFacingMac = publicFacingMac; | ||
| 57 | } | 65 | } |
| 58 | 66 | ||
| 59 | /** | 67 | /** |
| ... | @@ -73,4 +81,13 @@ public final class VbngConfiguration { | ... | @@ -73,4 +81,13 @@ public final class VbngConfiguration { |
| 73 | public IpAddress getNextHopIpAddress() { | 81 | public IpAddress getNextHopIpAddress() { |
| 74 | return nextHopIpAddress; | 82 | return nextHopIpAddress; |
| 75 | } | 83 | } |
| 84 | + | ||
| 85 | + /** | ||
| 86 | + * Gets the MAC address configured for all the public IP addresses. | ||
| 87 | + * | ||
| 88 | + * @return the MAC address | ||
| 89 | + */ | ||
| 90 | + public MacAddress getPublicFacingMac() { | ||
| 91 | + return publicFacingMac; | ||
| 92 | + } | ||
| 76 | } | 93 | } | ... | ... |
| ... | @@ -31,6 +31,7 @@ import org.apache.felix.scr.annotations.Deactivate; | ... | @@ -31,6 +31,7 @@ import org.apache.felix.scr.annotations.Deactivate; |
| 31 | import org.apache.felix.scr.annotations.Service; | 31 | import org.apache.felix.scr.annotations.Service; |
| 32 | import org.onlab.packet.IpAddress; | 32 | import org.onlab.packet.IpAddress; |
| 33 | import org.onlab.packet.IpPrefix; | 33 | import org.onlab.packet.IpPrefix; |
| 34 | +import org.onlab.packet.MacAddress; | ||
| 34 | import org.slf4j.Logger; | 35 | import org.slf4j.Logger; |
| 35 | import org.slf4j.LoggerFactory; | 36 | import org.slf4j.LoggerFactory; |
| 36 | 37 | ||
| ... | @@ -58,6 +59,7 @@ public class VbngConfigurationManager implements VbngConfigurationService { | ... | @@ -58,6 +59,7 @@ public class VbngConfigurationManager implements VbngConfigurationService { |
| 58 | new ConcurrentHashMap<>(); | 59 | new ConcurrentHashMap<>(); |
| 59 | 60 | ||
| 60 | private IpAddress nextHopIpAddress; | 61 | private IpAddress nextHopIpAddress; |
| 62 | + private MacAddress macOfPublicIpAddresses; | ||
| 61 | 63 | ||
| 62 | @Activate | 64 | @Activate |
| 63 | public void activate() { | 65 | public void activate() { |
| ... | @@ -96,6 +98,7 @@ public class VbngConfigurationManager implements VbngConfigurationService { | ... | @@ -96,6 +98,7 @@ public class VbngConfigurationManager implements VbngConfigurationService { |
| 96 | localPublicIpPrefixes.put(prefix, true); | 98 | localPublicIpPrefixes.put(prefix, true); |
| 97 | } | 99 | } |
| 98 | nextHopIpAddress = config.getNextHopIpAddress(); | 100 | nextHopIpAddress = config.getNextHopIpAddress(); |
| 101 | + macOfPublicIpAddresses = config.getPublicFacingMac(); | ||
| 99 | 102 | ||
| 100 | } catch (FileNotFoundException e) { | 103 | } catch (FileNotFoundException e) { |
| 101 | log.warn("Configuration file not found: {}", configFileName); | 104 | log.warn("Configuration file not found: {}", configFileName); |
| ... | @@ -109,6 +112,11 @@ public class VbngConfigurationManager implements VbngConfigurationService { | ... | @@ -109,6 +112,11 @@ public class VbngConfigurationManager implements VbngConfigurationService { |
| 109 | return nextHopIpAddress; | 112 | return nextHopIpAddress; |
| 110 | } | 113 | } |
| 111 | 114 | ||
| 115 | + @Override | ||
| 116 | + public MacAddress getPublicFacingMac() { | ||
| 117 | + return macOfPublicIpAddresses; | ||
| 118 | + } | ||
| 119 | + | ||
| 112 | // TODO handle the case: the number of public IP addresses is not enough | 120 | // TODO handle the case: the number of public IP addresses is not enough |
| 113 | // for 1:1 mapping from public IP to private IP. | 121 | // for 1:1 mapping from public IP to private IP. |
| 114 | @Override | 122 | @Override |
| ... | @@ -169,6 +177,11 @@ public class VbngConfigurationManager implements VbngConfigurationService { | ... | @@ -169,6 +177,11 @@ public class VbngConfigurationManager implements VbngConfigurationService { |
| 169 | return ipAddressMap.get(privateIpAddress); | 177 | return ipAddressMap.get(privateIpAddress); |
| 170 | } | 178 | } |
| 171 | 179 | ||
| 180 | + @Override | ||
| 181 | + public boolean isAssignedPublicIpAddress(IpAddress ipAddress) { | ||
| 182 | + return ipAddressMap.containsValue(ipAddress); | ||
| 183 | + } | ||
| 184 | + | ||
| 172 | /** | 185 | /** |
| 173 | * Generates a new IP address base on a given IP address plus a number to | 186 | * Generates a new IP address base on a given IP address plus a number to |
| 174 | * increase. | 187 | * increase. | ... | ... |
| ... | @@ -16,6 +16,7 @@ | ... | @@ -16,6 +16,7 @@ |
| 16 | package org.onosproject.virtualbng; | 16 | package org.onosproject.virtualbng; |
| 17 | 17 | ||
| 18 | import org.onlab.packet.IpAddress; | 18 | import org.onlab.packet.IpAddress; |
| 19 | +import org.onlab.packet.MacAddress; | ||
| 19 | 20 | ||
| 20 | /** | 21 | /** |
| 21 | * Provides information about the virtual BNG configuration. | 22 | * Provides information about the virtual BNG configuration. |
| ... | @@ -30,6 +31,22 @@ public interface VbngConfigurationService { | ... | @@ -30,6 +31,22 @@ public interface VbngConfigurationService { |
| 30 | public IpAddress getNextHopIpAddress(); | 31 | public IpAddress getNextHopIpAddress(); |
| 31 | 32 | ||
| 32 | /** | 33 | /** |
| 34 | + * Gets the MAC address configured for all the public IP addresses. | ||
| 35 | + * | ||
| 36 | + * @return the MAC address | ||
| 37 | + */ | ||
| 38 | + public MacAddress getPublicFacingMac(); | ||
| 39 | + | ||
| 40 | + /** | ||
| 41 | + * Evaluates whether an IP address is an assigned public IP address. | ||
| 42 | + * | ||
| 43 | + * @param ipAddress the IP address to evaluate | ||
| 44 | + * @return true if the input IP address is an assigned public IP address, | ||
| 45 | + * otherwise false | ||
| 46 | + */ | ||
| 47 | + public boolean isAssignedPublicIpAddress(IpAddress ipAddress); | ||
| 48 | + | ||
| 49 | + /** | ||
| 33 | * Gets an available public IP address from local public IP prefixes. | 50 | * Gets an available public IP address from local public IP prefixes. |
| 34 | * | 51 | * |
| 35 | * @param privateIpAddress a private IP address | 52 | * @param privateIpAddress a private IP address | ... | ... |
| 1 | +/* | ||
| 2 | + * Copyright 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.virtualbng; | ||
| 17 | + | ||
| 18 | +import static org.slf4j.LoggerFactory.getLogger; | ||
| 19 | + | ||
| 20 | +import java.nio.ByteBuffer; | ||
| 21 | + | ||
| 22 | +import org.apache.felix.scr.annotations.Activate; | ||
| 23 | +import org.apache.felix.scr.annotations.Component; | ||
| 24 | +import org.apache.felix.scr.annotations.Deactivate; | ||
| 25 | +import org.apache.felix.scr.annotations.Reference; | ||
| 26 | +import org.apache.felix.scr.annotations.ReferenceCardinality; | ||
| 27 | +import org.onlab.packet.ARP; | ||
| 28 | +import org.onlab.packet.Ethernet; | ||
| 29 | +import org.onlab.packet.Ip4Address; | ||
| 30 | +import org.onlab.packet.MacAddress; | ||
| 31 | +import org.onosproject.core.ApplicationId; | ||
| 32 | +import org.onosproject.core.CoreService; | ||
| 33 | +import org.onosproject.net.ConnectPoint; | ||
| 34 | +import org.onosproject.net.flow.DefaultTrafficSelector; | ||
| 35 | +import org.onosproject.net.flow.DefaultTrafficTreatment; | ||
| 36 | +import org.onosproject.net.flow.TrafficSelector; | ||
| 37 | +import org.onosproject.net.flow.TrafficTreatment; | ||
| 38 | +import org.onosproject.net.packet.DefaultOutboundPacket; | ||
| 39 | +import org.onosproject.net.packet.InboundPacket; | ||
| 40 | +import org.onosproject.net.packet.PacketContext; | ||
| 41 | +import org.onosproject.net.packet.PacketPriority; | ||
| 42 | +import org.onosproject.net.packet.PacketProcessor; | ||
| 43 | +import org.onosproject.net.packet.PacketService; | ||
| 44 | +import org.slf4j.Logger; | ||
| 45 | + | ||
| 46 | +/** | ||
| 47 | + * When the upstream gateway which is outside local SDN network wants to send | ||
| 48 | + * packets to our local public IP addresses, it will send out ARP requests to | ||
| 49 | + * get the MAC address of each public IP address. Actually, there are no hosts | ||
| 50 | + * configured with those public IP addresses, so this class is to emulate the | ||
| 51 | + * behavior of the non-existed hosts and return ARP replies. | ||
| 52 | + * <p> | ||
| 53 | + * Since we will rewrite the destination MAC address in the switch before | ||
| 54 | + * traffic packets go to the destination, so the MAC address can be any number. | ||
| 55 | + * We manually configured a random MAC address for this purpose in the vBNG | ||
| 56 | + * configuration file. | ||
| 57 | + * </p> | ||
| 58 | + */ | ||
| 59 | +@Component(immediate = true) | ||
| 60 | +public class VirtualPublicHosts { | ||
| 61 | + private final Logger log = getLogger(getClass()); | ||
| 62 | + | ||
| 63 | + private static final String APP_NAME = | ||
| 64 | + "org.onosproject.virtualbng.VirtualPublicHosts"; | ||
| 65 | + | ||
| 66 | + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) | ||
| 67 | + protected CoreService coreService; | ||
| 68 | + | ||
| 69 | + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) | ||
| 70 | + protected PacketService packetService; | ||
| 71 | + | ||
| 72 | + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) | ||
| 73 | + protected VbngConfigurationService vbngConfigService; | ||
| 74 | + | ||
| 75 | + private ApplicationId appId; | ||
| 76 | + private ArpRequestProcessor processor = new ArpRequestProcessor(); | ||
| 77 | + | ||
| 78 | + @Activate | ||
| 79 | + public void activate() { | ||
| 80 | + appId = coreService.registerApplication(APP_NAME); | ||
| 81 | + | ||
| 82 | + packetService.addProcessor(processor, | ||
| 83 | + PacketProcessor.ADVISOR_MAX + 6); | ||
| 84 | + | ||
| 85 | + TrafficSelector.Builder selector = DefaultTrafficSelector.builder(); | ||
| 86 | + // Only IPv4 is supported in current vBNG. | ||
| 87 | + selector.matchEthType(Ethernet.TYPE_ARP); | ||
| 88 | + packetService.requestPackets(selector.build(), | ||
| 89 | + PacketPriority.REACTIVE, appId); | ||
| 90 | + | ||
| 91 | + log.info("vBNG virtual public hosts started"); | ||
| 92 | + } | ||
| 93 | + | ||
| 94 | + @Deactivate | ||
| 95 | + public void deactivate() { | ||
| 96 | + packetService.removeProcessor(processor); | ||
| 97 | + processor = null; | ||
| 98 | + log.info("vBNG virtual public hosts Stopped"); | ||
| 99 | + } | ||
| 100 | + | ||
| 101 | + /** | ||
| 102 | + * This class filters out the ARP request packets, generates the ARP | ||
| 103 | + * reply packets, and emits those packets. | ||
| 104 | + */ | ||
| 105 | + private class ArpRequestProcessor implements PacketProcessor { | ||
| 106 | + @Override | ||
| 107 | + public void process(PacketContext context) { | ||
| 108 | + | ||
| 109 | + InboundPacket pkt = context.inPacket(); | ||
| 110 | + Ethernet ethPkt = pkt.parsed(); | ||
| 111 | + | ||
| 112 | + // Only handle the ARP packets | ||
| 113 | + if (ethPkt == null || ethPkt.getEtherType() != Ethernet.TYPE_ARP) { | ||
| 114 | + return; | ||
| 115 | + } | ||
| 116 | + ARP arpPacket = (ARP) ethPkt.getPayload(); | ||
| 117 | + // Only handle ARP request packets | ||
| 118 | + if (arpPacket.getOpCode() != ARP.OP_REQUEST) { | ||
| 119 | + return; | ||
| 120 | + } | ||
| 121 | + | ||
| 122 | + Ip4Address targetIpAddress = Ip4Address | ||
| 123 | + .valueOf(arpPacket.getTargetProtocolAddress()); | ||
| 124 | + | ||
| 125 | + // Only handle an ARP request when the target IP address inside is | ||
| 126 | + // an assigned public IP address | ||
| 127 | + if (!vbngConfigService.isAssignedPublicIpAddress(targetIpAddress)) { | ||
| 128 | + return; | ||
| 129 | + } | ||
| 130 | + | ||
| 131 | + MacAddress virtualHostMac = | ||
| 132 | + vbngConfigService.getPublicFacingMac(); | ||
| 133 | + if (virtualHostMac == null) { | ||
| 134 | + return; | ||
| 135 | + } | ||
| 136 | + | ||
| 137 | + ConnectPoint srcConnectPoint = pkt.receivedFrom(); | ||
| 138 | + Ethernet eth = ARP.buildArpReply(targetIpAddress, | ||
| 139 | + virtualHostMac, | ||
| 140 | + ethPkt); | ||
| 141 | + | ||
| 142 | + TrafficTreatment.Builder builder = | ||
| 143 | + DefaultTrafficTreatment.builder(); | ||
| 144 | + builder.setOutput(srcConnectPoint.port()); | ||
| 145 | + packetService.emit(new DefaultOutboundPacket( | ||
| 146 | + srcConnectPoint.deviceId(), | ||
| 147 | + builder.build(), | ||
| 148 | + ByteBuffer.wrap(eth.serialize()))); | ||
| 149 | + } | ||
| 150 | + } | ||
| 151 | +} |
-
Please register or login to post a comment