Committed by
Gerrit Code Review
Route CLI improvements and bug fixes
Change-Id: I4b4547f578cc053dc150066dadb68b6b2cbb82ee
Showing
10 changed files
with
280 additions
and
7 deletions
| 1 | +/* | ||
| 2 | + * Copyright 2016 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 | + | ||
| 17 | +package org.onosproject.cli.net; | ||
| 18 | + | ||
| 19 | +import org.apache.karaf.shell.commands.Command; | ||
| 20 | +import org.onosproject.cli.AbstractShellCommand; | ||
| 21 | +import org.onosproject.incubator.net.routing.NextHop; | ||
| 22 | +import org.onosproject.incubator.net.routing.Route; | ||
| 23 | +import org.onosproject.incubator.net.routing.RouteService; | ||
| 24 | + | ||
| 25 | +import java.util.Collection; | ||
| 26 | +import java.util.Set; | ||
| 27 | + | ||
| 28 | +/** | ||
| 29 | + * Command to show information about routing next hops. | ||
| 30 | + */ | ||
| 31 | +@Command(scope = "onos", name = "next-hops", | ||
| 32 | + description = "Lists all next hops in the route store") | ||
| 33 | +public class NextHopsListCommand extends AbstractShellCommand { | ||
| 34 | + | ||
| 35 | + private static final String FORMAT_HEADER = | ||
| 36 | + " Network Next Hop"; | ||
| 37 | + private static final String FORMAT_ROUTE = | ||
| 38 | + " %-18s %-15s"; | ||
| 39 | + | ||
| 40 | + private static final String FORMAT_TABLE = "Table: %s"; | ||
| 41 | + private static final String FORMAT_TOTAL = " Total: %d"; | ||
| 42 | + | ||
| 43 | + private static final String FORMAT = "ip=%s, mac=%s, numRoutes=%s"; | ||
| 44 | + | ||
| 45 | + @Override | ||
| 46 | + protected void execute() { | ||
| 47 | + RouteService service = AbstractShellCommand.get(RouteService.class); | ||
| 48 | + | ||
| 49 | + Set<NextHop> nextHops = service.getNextHops(); | ||
| 50 | + | ||
| 51 | + nextHops.forEach(nextHop -> { | ||
| 52 | + Collection<Route> routes = service.getRoutesForNextHop(nextHop.ip()); | ||
| 53 | + print(FORMAT, nextHop.ip(), nextHop.mac(), routes.size()); | ||
| 54 | + }); | ||
| 55 | + | ||
| 56 | + } | ||
| 57 | + | ||
| 58 | +} |
| ... | @@ -18,6 +18,7 @@ package org.onosproject.cli.net; | ... | @@ -18,6 +18,7 @@ package org.onosproject.cli.net; |
| 18 | 18 | ||
| 19 | import org.apache.karaf.shell.commands.Argument; | 19 | import org.apache.karaf.shell.commands.Argument; |
| 20 | import org.apache.karaf.shell.commands.Command; | 20 | import org.apache.karaf.shell.commands.Command; |
| 21 | +import org.onlab.packet.IpAddress; | ||
| 21 | import org.onlab.packet.IpPrefix; | 22 | import org.onlab.packet.IpPrefix; |
| 22 | import org.onosproject.cli.AbstractShellCommand; | 23 | import org.onosproject.cli.AbstractShellCommand; |
| 23 | import org.onosproject.incubator.net.routing.Route; | 24 | import org.onosproject.incubator.net.routing.Route; |
| ... | @@ -36,13 +37,18 @@ public class RouteRemoveCommand extends AbstractShellCommand { | ... | @@ -36,13 +37,18 @@ public class RouteRemoveCommand extends AbstractShellCommand { |
| 36 | required = true) | 37 | required = true) |
| 37 | String prefixString = null; | 38 | String prefixString = null; |
| 38 | 39 | ||
| 40 | + @Argument(index = 1, name = "prefix", description = "Next hop IP address", | ||
| 41 | + required = true) | ||
| 42 | + String nextHopString = null; | ||
| 43 | + | ||
| 39 | @Override | 44 | @Override |
| 40 | protected void execute() { | 45 | protected void execute() { |
| 41 | RouteAdminService service = AbstractShellCommand.get(RouteAdminService.class); | 46 | RouteAdminService service = AbstractShellCommand.get(RouteAdminService.class); |
| 42 | 47 | ||
| 43 | IpPrefix prefix = IpPrefix.valueOf(prefixString); | 48 | IpPrefix prefix = IpPrefix.valueOf(prefixString); |
| 49 | + IpAddress nextHop = IpAddress.valueOf(nextHopString); | ||
| 44 | 50 | ||
| 45 | - service.withdraw(Collections.singleton(new Route(Route.Source.STATIC, prefix, null))); | 51 | + service.withdraw(Collections.singleton(new Route(Route.Source.STATIC, prefix, nextHop))); |
| 46 | } | 52 | } |
| 47 | 53 | ||
| 48 | } | 54 | } | ... | ... |
| ... | @@ -505,6 +505,9 @@ | ... | @@ -505,6 +505,9 @@ |
| 505 | <command> | 505 | <command> |
| 506 | <action class="org.onosproject.cli.net.RouteRemoveCommand"/> | 506 | <action class="org.onosproject.cli.net.RouteRemoveCommand"/> |
| 507 | </command> | 507 | </command> |
| 508 | + <command> | ||
| 509 | + <action class="org.onosproject.cli.net.NextHopsListCommand"/> | ||
| 510 | + </command> | ||
| 508 | 511 | ||
| 509 | <command> | 512 | <command> |
| 510 | <action class="org.onosproject.cli.net.GlobalLabelCommand"/> | 513 | <action class="org.onosproject.cli.net.GlobalLabelCommand"/> | ... | ... |
| 1 | +/* | ||
| 2 | + * Copyright 2016 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 | + | ||
| 17 | +package org.onosproject.incubator.net.routing; | ||
| 18 | + | ||
| 19 | +import org.onlab.packet.IpAddress; | ||
| 20 | +import org.onlab.packet.MacAddress; | ||
| 21 | + | ||
| 22 | +import java.util.Objects; | ||
| 23 | + | ||
| 24 | +import static com.google.common.base.MoreObjects.toStringHelper; | ||
| 25 | + | ||
| 26 | +/** | ||
| 27 | + * Describes a routing next hop. | ||
| 28 | + */ | ||
| 29 | +public class NextHop { | ||
| 30 | + | ||
| 31 | + private final IpAddress ip; | ||
| 32 | + private final MacAddress mac; | ||
| 33 | + | ||
| 34 | + /** | ||
| 35 | + * Creates a new next hop. | ||
| 36 | + * | ||
| 37 | + * @param ip IP address | ||
| 38 | + * @param mac MAC address | ||
| 39 | + */ | ||
| 40 | + public NextHop(IpAddress ip, MacAddress mac) { | ||
| 41 | + this.ip = ip; | ||
| 42 | + this.mac = mac; | ||
| 43 | + } | ||
| 44 | + | ||
| 45 | + /** | ||
| 46 | + * Returns the IP address of the next hop. | ||
| 47 | + * | ||
| 48 | + * @return IP address | ||
| 49 | + */ | ||
| 50 | + public IpAddress ip() { | ||
| 51 | + return ip; | ||
| 52 | + } | ||
| 53 | + | ||
| 54 | + /** | ||
| 55 | + * Returns the MAC address of the next hop. | ||
| 56 | + * | ||
| 57 | + * @return MAC address | ||
| 58 | + */ | ||
| 59 | + public MacAddress mac() { | ||
| 60 | + return mac; | ||
| 61 | + } | ||
| 62 | + | ||
| 63 | + @Override | ||
| 64 | + public int hashCode() { | ||
| 65 | + return Objects.hash(ip, mac); | ||
| 66 | + } | ||
| 67 | + | ||
| 68 | + @Override | ||
| 69 | + public boolean equals(Object other) { | ||
| 70 | + if (this == other) { | ||
| 71 | + return true; | ||
| 72 | + } | ||
| 73 | + | ||
| 74 | + if (!(other instanceof NextHop)) { | ||
| 75 | + return false; | ||
| 76 | + } | ||
| 77 | + | ||
| 78 | + NextHop that = (NextHop) other; | ||
| 79 | + | ||
| 80 | + return Objects.equals(this.ip, that.mac) && | ||
| 81 | + Objects.equals(this.ip, that.mac); | ||
| 82 | + } | ||
| 83 | + | ||
| 84 | + @Override | ||
| 85 | + public String toString() { | ||
| 86 | + return toStringHelper(this) | ||
| 87 | + .add("ip", ip) | ||
| 88 | + .add("mac", mac) | ||
| 89 | + .toString(); | ||
| 90 | + } | ||
| 91 | +} |
| ... | @@ -20,6 +20,8 @@ import org.onlab.packet.IpAddress; | ... | @@ -20,6 +20,8 @@ import org.onlab.packet.IpAddress; |
| 20 | import org.onlab.packet.IpPrefix; | 20 | import org.onlab.packet.IpPrefix; |
| 21 | import org.onlab.packet.MacAddress; | 21 | import org.onlab.packet.MacAddress; |
| 22 | 22 | ||
| 23 | +import static com.google.common.base.MoreObjects.toStringHelper; | ||
| 24 | + | ||
| 23 | /** | 25 | /** |
| 24 | * Represents a route with the next hop MAC address resolved. | 26 | * Represents a route with the next hop MAC address resolved. |
| 25 | */ | 27 | */ |
| ... | @@ -80,4 +82,13 @@ public class ResolvedRoute { | ... | @@ -80,4 +82,13 @@ public class ResolvedRoute { |
| 80 | public MacAddress nextHopMac() { | 82 | public MacAddress nextHopMac() { |
| 81 | return nextHopMac; | 83 | return nextHopMac; |
| 82 | } | 84 | } |
| 85 | + | ||
| 86 | + @Override | ||
| 87 | + public String toString() { | ||
| 88 | + return toStringHelper(this) | ||
| 89 | + .add("prefix", prefix) | ||
| 90 | + .add("nextHop", nextHop) | ||
| 91 | + .add("nextHopMac", nextHopMac) | ||
| 92 | + .toString(); | ||
| 93 | + } | ||
| 83 | } | 94 | } | ... | ... |
| ... | @@ -21,6 +21,7 @@ import org.onlab.packet.IpPrefix; | ... | @@ -21,6 +21,7 @@ import org.onlab.packet.IpPrefix; |
| 21 | 21 | ||
| 22 | import java.util.Objects; | 22 | import java.util.Objects; |
| 23 | 23 | ||
| 24 | +import static com.google.common.base.MoreObjects.toStringHelper; | ||
| 24 | import static com.google.common.base.Preconditions.checkArgument; | 25 | import static com.google.common.base.Preconditions.checkArgument; |
| 25 | import static com.google.common.base.Preconditions.checkNotNull; | 26 | import static com.google.common.base.Preconditions.checkNotNull; |
| 26 | 27 | ||
| ... | @@ -70,7 +71,8 @@ public class Route { | ... | @@ -70,7 +71,8 @@ public class Route { |
| 70 | */ | 71 | */ |
| 71 | public Route(Source source, IpPrefix prefix, IpAddress nextHop) { | 72 | public Route(Source source, IpPrefix prefix, IpAddress nextHop) { |
| 72 | checkNotNull(prefix); | 73 | checkNotNull(prefix); |
| 73 | - checkArgument(nextHop == null || prefix.version().equals(nextHop.version()), VERSION_MISMATCH); | 74 | + checkNotNull(nextHop); |
| 75 | + checkArgument(prefix.version().equals(nextHop.version()), VERSION_MISMATCH); | ||
| 74 | 76 | ||
| 75 | this.source = checkNotNull(source); | 77 | this.source = checkNotNull(source); |
| 76 | this.prefix = prefix; | 78 | this.prefix = prefix; |
| ... | @@ -124,4 +126,12 @@ public class Route { | ... | @@ -124,4 +126,12 @@ public class Route { |
| 124 | return Objects.equals(this.prefix, that.prefix) && | 126 | return Objects.equals(this.prefix, that.prefix) && |
| 125 | Objects.equals(this.nextHop, that.nextHop); | 127 | Objects.equals(this.nextHop, that.nextHop); |
| 126 | } | 128 | } |
| 129 | + | ||
| 130 | + @Override | ||
| 131 | + public String toString() { | ||
| 132 | + return toStringHelper(this) | ||
| 133 | + .add("prefix", prefix) | ||
| 134 | + .add("nextHop", nextHop) | ||
| 135 | + .toString(); | ||
| 136 | + } | ||
| 127 | } | 137 | } | ... | ... |
| ... | @@ -21,6 +21,7 @@ import org.onosproject.event.ListenerService; | ... | @@ -21,6 +21,7 @@ import org.onosproject.event.ListenerService; |
| 21 | 21 | ||
| 22 | import java.util.Collection; | 22 | import java.util.Collection; |
| 23 | import java.util.Map; | 23 | import java.util.Map; |
| 24 | +import java.util.Set; | ||
| 24 | 25 | ||
| 25 | /** | 26 | /** |
| 26 | * Unicast IP route service. | 27 | * Unicast IP route service. |
| ... | @@ -44,4 +45,19 @@ public interface RouteService extends ListenerService<RouteEvent, RouteListener> | ... | @@ -44,4 +45,19 @@ public interface RouteService extends ListenerService<RouteEvent, RouteListener> |
| 44 | */ | 45 | */ |
| 45 | Route longestPrefixMatch(IpAddress ip); | 46 | Route longestPrefixMatch(IpAddress ip); |
| 46 | 47 | ||
| 48 | + /** | ||
| 49 | + * Returns the routes for the given next hop. | ||
| 50 | + * | ||
| 51 | + * @param nextHop next hop IP address | ||
| 52 | + * @return routes for this next hop | ||
| 53 | + */ | ||
| 54 | + Collection<Route> getRoutesForNextHop(IpAddress nextHop); | ||
| 55 | + | ||
| 56 | + /** | ||
| 57 | + * Returns all next hops in the route store. | ||
| 58 | + * | ||
| 59 | + * @return set of next hops | ||
| 60 | + */ | ||
| 61 | + Set<NextHop> getNextHops(); | ||
| 62 | + | ||
| 47 | } | 63 | } | ... | ... |
| ... | @@ -21,6 +21,7 @@ import org.onlab.packet.MacAddress; | ... | @@ -21,6 +21,7 @@ import org.onlab.packet.MacAddress; |
| 21 | import org.onosproject.store.Store; | 21 | import org.onosproject.store.Store; |
| 22 | 22 | ||
| 23 | import java.util.Collection; | 23 | import java.util.Collection; |
| 24 | +import java.util.Map; | ||
| 24 | import java.util.Set; | 25 | import java.util.Set; |
| 25 | 26 | ||
| 26 | /** | 27 | /** |
| ... | @@ -66,6 +67,14 @@ public interface RouteStore extends Store<RouteEvent, RouteStoreDelegate> { | ... | @@ -66,6 +67,14 @@ public interface RouteStore extends Store<RouteEvent, RouteStoreDelegate> { |
| 66 | Route longestPrefixMatch(IpAddress ip); | 67 | Route longestPrefixMatch(IpAddress ip); |
| 67 | 68 | ||
| 68 | /** | 69 | /** |
| 70 | + * Returns the routes that point to the given next hop IP address. | ||
| 71 | + * | ||
| 72 | + * @param ip IP address of the next hop | ||
| 73 | + * @return routes for the given next hop | ||
| 74 | + */ | ||
| 75 | + Collection<Route> getRoutesForNextHop(IpAddress ip); | ||
| 76 | + | ||
| 77 | + /** | ||
| 69 | * Updates a next hop IP and MAC in the store. | 78 | * Updates a next hop IP and MAC in the store. |
| 70 | * | 79 | * |
| 71 | * @param ip IP address | 80 | * @param ip IP address |
| ... | @@ -88,4 +97,11 @@ public interface RouteStore extends Store<RouteEvent, RouteStoreDelegate> { | ... | @@ -88,4 +97,11 @@ public interface RouteStore extends Store<RouteEvent, RouteStoreDelegate> { |
| 88 | * @return MAC address | 97 | * @return MAC address |
| 89 | */ | 98 | */ |
| 90 | MacAddress getNextHop(IpAddress ip); | 99 | MacAddress getNextHop(IpAddress ip); |
| 100 | + | ||
| 101 | + /** | ||
| 102 | + * Returns all next hops in the route store. | ||
| 103 | + * | ||
| 104 | + * @return next hops | ||
| 105 | + */ | ||
| 106 | + Map<IpAddress, MacAddress> getNextHops(); | ||
| 91 | } | 107 | } | ... | ... |
| ... | @@ -25,6 +25,7 @@ import org.apache.felix.scr.annotations.Service; | ... | @@ -25,6 +25,7 @@ import org.apache.felix.scr.annotations.Service; |
| 25 | import org.onlab.packet.IpAddress; | 25 | import org.onlab.packet.IpAddress; |
| 26 | import org.onlab.packet.MacAddress; | 26 | import org.onlab.packet.MacAddress; |
| 27 | import org.onosproject.event.ListenerService; | 27 | import org.onosproject.event.ListenerService; |
| 28 | +import org.onosproject.incubator.net.routing.NextHop; | ||
| 28 | import org.onosproject.incubator.net.routing.ResolvedRoute; | 29 | import org.onosproject.incubator.net.routing.ResolvedRoute; |
| 29 | import org.onosproject.incubator.net.routing.Route; | 30 | import org.onosproject.incubator.net.routing.Route; |
| 30 | import org.onosproject.incubator.net.routing.RouteAdminService; | 31 | import org.onosproject.incubator.net.routing.RouteAdminService; |
| ... | @@ -146,6 +147,7 @@ public class RouteManager implements ListenerService<RouteEvent, RouteListener>, | ... | @@ -146,6 +147,7 @@ public class RouteManager implements ListenerService<RouteEvent, RouteListener>, |
| 146 | * @param event event | 147 | * @param event event |
| 147 | */ | 148 | */ |
| 148 | private void post(RouteEvent event) { | 149 | private void post(RouteEvent event) { |
| 150 | + log.debug("Sending event {}", event); | ||
| 149 | synchronized (this) { | 151 | synchronized (this) { |
| 150 | listeners.values().forEach(l -> l.post(event)); | 152 | listeners.values().forEach(l -> l.post(event)); |
| 151 | } | 153 | } |
| ... | @@ -165,9 +167,22 @@ public class RouteManager implements ListenerService<RouteEvent, RouteListener>, | ... | @@ -165,9 +167,22 @@ public class RouteManager implements ListenerService<RouteEvent, RouteListener>, |
| 165 | } | 167 | } |
| 166 | 168 | ||
| 167 | @Override | 169 | @Override |
| 170 | + public Collection<Route> getRoutesForNextHop(IpAddress nextHop) { | ||
| 171 | + return routeStore.getRoutesForNextHop(nextHop); | ||
| 172 | + } | ||
| 173 | + | ||
| 174 | + @Override | ||
| 175 | + public Set<NextHop> getNextHops() { | ||
| 176 | + return routeStore.getNextHops().entrySet().stream() | ||
| 177 | + .map(entry -> new NextHop(entry.getKey(), entry.getValue())) | ||
| 178 | + .collect(Collectors.toSet()); | ||
| 179 | + } | ||
| 180 | + | ||
| 181 | + @Override | ||
| 168 | public void update(Collection<Route> routes) { | 182 | public void update(Collection<Route> routes) { |
| 169 | synchronized (this) { | 183 | synchronized (this) { |
| 170 | routes.forEach(route -> { | 184 | routes.forEach(route -> { |
| 185 | + log.debug("Received update {}", route); | ||
| 171 | routeStore.updateRoute(route); | 186 | routeStore.updateRoute(route); |
| 172 | resolve(route); | 187 | resolve(route); |
| 173 | }); | 188 | }); |
| ... | @@ -177,7 +192,10 @@ public class RouteManager implements ListenerService<RouteEvent, RouteListener>, | ... | @@ -177,7 +192,10 @@ public class RouteManager implements ListenerService<RouteEvent, RouteListener>, |
| 177 | @Override | 192 | @Override |
| 178 | public void withdraw(Collection<Route> routes) { | 193 | public void withdraw(Collection<Route> routes) { |
| 179 | synchronized (this) { | 194 | synchronized (this) { |
| 180 | - routes.forEach(route -> routeStore.removeRoute(route)); | 195 | + routes.forEach(route -> { |
| 196 | + log.debug("Received withdraw {}", routes); | ||
| 197 | + routeStore.removeRoute(route); | ||
| 198 | + }); | ||
| 181 | } | 199 | } |
| 182 | } | 200 | } |
| 183 | 201 | ... | ... |
| ... | @@ -17,8 +17,10 @@ | ... | @@ -17,8 +17,10 @@ |
| 17 | package org.onosproject.incubator.store.routing.impl; | 17 | package org.onosproject.incubator.store.routing.impl; |
| 18 | 18 | ||
| 19 | import com.google.common.collect.HashMultimap; | 19 | import com.google.common.collect.HashMultimap; |
| 20 | +import com.google.common.collect.ImmutableMap; | ||
| 20 | import com.google.common.collect.Multimap; | 21 | import com.google.common.collect.Multimap; |
| 21 | import com.google.common.collect.Multimaps; | 22 | import com.google.common.collect.Multimaps; |
| 23 | +import com.googlecode.concurrenttrees.common.KeyValuePair; | ||
| 22 | import com.googlecode.concurrenttrees.radix.node.concrete.DefaultByteArrayNodeFactory; | 24 | import com.googlecode.concurrenttrees.radix.node.concrete.DefaultByteArrayNodeFactory; |
| 23 | import com.googlecode.concurrenttrees.radixinverted.ConcurrentInvertedRadixTree; | 25 | import com.googlecode.concurrenttrees.radixinverted.ConcurrentInvertedRadixTree; |
| 24 | import com.googlecode.concurrenttrees.radixinverted.InvertedRadixTree; | 26 | import com.googlecode.concurrenttrees.radixinverted.InvertedRadixTree; |
| ... | @@ -35,10 +37,14 @@ import org.onosproject.incubator.net.routing.RouteStore; | ... | @@ -35,10 +37,14 @@ import org.onosproject.incubator.net.routing.RouteStore; |
| 35 | import org.onosproject.incubator.net.routing.RouteStoreDelegate; | 37 | import org.onosproject.incubator.net.routing.RouteStoreDelegate; |
| 36 | import org.onosproject.incubator.net.routing.RouteTableId; | 38 | import org.onosproject.incubator.net.routing.RouteTableId; |
| 37 | import org.onosproject.store.AbstractStore; | 39 | import org.onosproject.store.AbstractStore; |
| 40 | +import org.slf4j.Logger; | ||
| 41 | +import org.slf4j.LoggerFactory; | ||
| 38 | 42 | ||
| 39 | import java.util.Collection; | 43 | import java.util.Collection; |
| 40 | import java.util.Collections; | 44 | import java.util.Collections; |
| 41 | import java.util.Iterator; | 45 | import java.util.Iterator; |
| 46 | +import java.util.LinkedList; | ||
| 47 | +import java.util.List; | ||
| 42 | import java.util.Map; | 48 | import java.util.Map; |
| 43 | import java.util.Set; | 49 | import java.util.Set; |
| 44 | import java.util.concurrent.ConcurrentHashMap; | 50 | import java.util.concurrent.ConcurrentHashMap; |
| ... | @@ -51,6 +57,8 @@ import java.util.concurrent.ConcurrentHashMap; | ... | @@ -51,6 +57,8 @@ import java.util.concurrent.ConcurrentHashMap; |
| 51 | public class LocalRouteStore extends AbstractStore<RouteEvent, RouteStoreDelegate> | 57 | public class LocalRouteStore extends AbstractStore<RouteEvent, RouteStoreDelegate> |
| 52 | implements RouteStore { | 58 | implements RouteStore { |
| 53 | 59 | ||
| 60 | + private Logger log = LoggerFactory.getLogger(getClass()); | ||
| 61 | + | ||
| 54 | private Map<RouteTableId, RouteTable> routeTables; | 62 | private Map<RouteTableId, RouteTable> routeTables; |
| 55 | private static final RouteTableId IPV4 = new RouteTableId("ipv4"); | 63 | private static final RouteTableId IPV4 = new RouteTableId("ipv4"); |
| 56 | private static final RouteTableId IPV6 = new RouteTableId("ipv6"); | 64 | private static final RouteTableId IPV6 = new RouteTableId("ipv6"); |
| ... | @@ -74,7 +82,9 @@ public class LocalRouteStore extends AbstractStore<RouteEvent, RouteStoreDelegat | ... | @@ -74,7 +82,9 @@ public class LocalRouteStore extends AbstractStore<RouteEvent, RouteStoreDelegat |
| 74 | public void removeRoute(Route route) { | 82 | public void removeRoute(Route route) { |
| 75 | RouteTable table = getDefaultRouteTable(route); | 83 | RouteTable table = getDefaultRouteTable(route); |
| 76 | table.remove(route); | 84 | table.remove(route); |
| 77 | - if (table.getRoutesForNextHop(route.nextHop()).isEmpty()) { | 85 | + Collection<Route> routes = table.getRoutesForNextHop(route.nextHop()); |
| 86 | + | ||
| 87 | + if (routes.isEmpty()) { | ||
| 78 | nextHops.remove(route.nextHop()); | 88 | nextHops.remove(route.nextHop()); |
| 79 | } | 89 | } |
| 80 | } | 90 | } |
| ... | @@ -99,8 +109,14 @@ public class LocalRouteStore extends AbstractStore<RouteEvent, RouteStoreDelegat | ... | @@ -99,8 +109,14 @@ public class LocalRouteStore extends AbstractStore<RouteEvent, RouteStoreDelegat |
| 99 | } | 109 | } |
| 100 | 110 | ||
| 101 | @Override | 111 | @Override |
| 112 | + public Collection<Route> getRoutesForNextHop(IpAddress ip) { | ||
| 113 | + return getDefaultRouteTable(ip).getRoutesForNextHop(ip); | ||
| 114 | + } | ||
| 115 | + | ||
| 116 | + @Override | ||
| 102 | public void updateNextHop(IpAddress ip, MacAddress mac) { | 117 | public void updateNextHop(IpAddress ip, MacAddress mac) { |
| 103 | Collection<Route> routes = getDefaultRouteTable(ip).getRoutesForNextHop(ip); | 118 | Collection<Route> routes = getDefaultRouteTable(ip).getRoutesForNextHop(ip); |
| 119 | + | ||
| 104 | if (!routes.isEmpty() && !mac.equals(nextHops.get(ip))) { | 120 | if (!routes.isEmpty() && !mac.equals(nextHops.get(ip))) { |
| 105 | nextHops.put(ip, mac); | 121 | nextHops.put(ip, mac); |
| 106 | 122 | ||
| ... | @@ -125,6 +141,11 @@ public class LocalRouteStore extends AbstractStore<RouteEvent, RouteStoreDelegat | ... | @@ -125,6 +141,11 @@ public class LocalRouteStore extends AbstractStore<RouteEvent, RouteStoreDelegat |
| 125 | return nextHops.get(ip); | 141 | return nextHops.get(ip); |
| 126 | } | 142 | } |
| 127 | 143 | ||
| 144 | + @Override | ||
| 145 | + public Map<IpAddress, MacAddress> getNextHops() { | ||
| 146 | + return ImmutableMap.copyOf(nextHops); | ||
| 147 | + } | ||
| 148 | + | ||
| 128 | private RouteTable getDefaultRouteTable(Route route) { | 149 | private RouteTable getDefaultRouteTable(Route route) { |
| 129 | return getDefaultRouteTable(route.prefix().address()); | 150 | return getDefaultRouteTable(route.prefix().address()); |
| 130 | } | 151 | } |
| ... | @@ -179,14 +200,27 @@ public class LocalRouteStore extends AbstractStore<RouteEvent, RouteStoreDelegat | ... | @@ -179,14 +200,27 @@ public class LocalRouteStore extends AbstractStore<RouteEvent, RouteStoreDelegat |
| 179 | routeTable.put(createBinaryString(route.prefix()), route); | 200 | routeTable.put(createBinaryString(route.prefix()), route); |
| 180 | 201 | ||
| 181 | // TODO manage routes from multiple providers | 202 | // TODO manage routes from multiple providers |
| 182 | - reverseIndex.remove(route.nextHop(), oldRoute); | 203 | + |
| 183 | reverseIndex.put(route.nextHop(), route); | 204 | reverseIndex.put(route.nextHop(), route); |
| 184 | 205 | ||
| 206 | + if (oldRoute != null) { | ||
| 207 | + reverseIndex.remove(oldRoute.nextHop(), oldRoute); | ||
| 208 | + | ||
| 209 | + if (reverseIndex.get(oldRoute.nextHop()).isEmpty()) { | ||
| 210 | + nextHops.remove(oldRoute.nextHop()); | ||
| 211 | + } | ||
| 212 | + } | ||
| 213 | + | ||
| 185 | if (oldRoute != null && !oldRoute.nextHop().equals(route.nextHop())) { | 214 | if (oldRoute != null && !oldRoute.nextHop().equals(route.nextHop())) { |
| 186 | // Remove old route because new one is different | 215 | // Remove old route because new one is different |
| 187 | // TODO ROUTE_UPDATED? | 216 | // TODO ROUTE_UPDATED? |
| 188 | notifyDelegate(new RouteEvent(RouteEvent.Type.ROUTE_REMOVED, new ResolvedRoute(oldRoute, null))); | 217 | notifyDelegate(new RouteEvent(RouteEvent.Type.ROUTE_REMOVED, new ResolvedRoute(oldRoute, null))); |
| 189 | } | 218 | } |
| 219 | + | ||
| 220 | + MacAddress nextHopMac = nextHops.get(route.nextHop()); | ||
| 221 | + if (nextHopMac != null) { | ||
| 222 | + notifyDelegate(new RouteEvent(RouteEvent.Type.ROUTE_UPDATED, new ResolvedRoute(route, nextHopMac))); | ||
| 223 | + } | ||
| 190 | } | 224 | } |
| 191 | } | 225 | } |
| 192 | 226 | ||
| ... | @@ -199,9 +233,9 @@ public class LocalRouteStore extends AbstractStore<RouteEvent, RouteStoreDelegat | ... | @@ -199,9 +233,9 @@ public class LocalRouteStore extends AbstractStore<RouteEvent, RouteStoreDelegat |
| 199 | synchronized (this) { | 233 | synchronized (this) { |
| 200 | Route removed = routes.remove(route.prefix()); | 234 | Route removed = routes.remove(route.prefix()); |
| 201 | routeTable.remove(createBinaryString(route.prefix())); | 235 | routeTable.remove(createBinaryString(route.prefix())); |
| 202 | - reverseIndex.remove(route.nextHop(), route); | ||
| 203 | 236 | ||
| 204 | if (removed != null) { | 237 | if (removed != null) { |
| 238 | + reverseIndex.remove(removed.nextHop(), removed); | ||
| 205 | notifyDelegate(new RouteEvent(RouteEvent.Type.ROUTE_REMOVED, new ResolvedRoute(route, null))); | 239 | notifyDelegate(new RouteEvent(RouteEvent.Type.ROUTE_REMOVED, new ResolvedRoute(route, null))); |
| 206 | } | 240 | } |
| 207 | } | 241 | } |
| ... | @@ -223,7 +257,17 @@ public class LocalRouteStore extends AbstractStore<RouteEvent, RouteStoreDelegat | ... | @@ -223,7 +257,17 @@ public class LocalRouteStore extends AbstractStore<RouteEvent, RouteStoreDelegat |
| 223 | * @return all routes | 257 | * @return all routes |
| 224 | */ | 258 | */ |
| 225 | public Collection<Route> getRoutes() { | 259 | public Collection<Route> getRoutes() { |
| 226 | - return routes.values(); | 260 | + Iterator<KeyValuePair<Route>> it = |
| 261 | + routeTable.getKeyValuePairsForKeysStartingWith("").iterator(); | ||
| 262 | + | ||
| 263 | + List<Route> routes = new LinkedList<>(); | ||
| 264 | + | ||
| 265 | + while (it.hasNext()) { | ||
| 266 | + KeyValuePair<Route> entry = it.next(); | ||
| 267 | + routes.add(entry.getValue()); | ||
| 268 | + } | ||
| 269 | + | ||
| 270 | + return routes; | ||
| 227 | } | 271 | } |
| 228 | 272 | ||
| 229 | /** | 273 | /** | ... | ... |
-
Please register or login to post a comment