blob: cb7ff17244f0a036916be6e89426b2c398ecfe8b [file] [log] [blame]
Jonathan Hartbfc5c482016-04-05 18:57:00 -07001/*
Brian O'Connora09fe5b2017-08-03 21:12:30 -07002 * Copyright 2017-present Open Networking Foundation
Jonathan Hartbfc5c482016-04-05 18:57:00 -07003 *
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 */
Ray Milkey69ec8712017-08-08 13:00:43 -070016package org.onosproject.routeservice.cli;
Jonathan Hartbfc5c482016-04-05 18:57:00 -070017
Jonathan Hartb2111342016-04-20 16:57:37 -070018import com.fasterxml.jackson.databind.JsonNode;
19import com.fasterxml.jackson.databind.ObjectMapper;
20import com.fasterxml.jackson.databind.node.ArrayNode;
21import com.fasterxml.jackson.databind.node.ObjectNode;
Ray Milkey86ad7bb2018-09-27 12:32:28 -070022import org.apache.karaf.shell.api.action.Command;
Ray Milkey7a2dee52018-09-28 10:58:28 -070023import org.apache.karaf.shell.api.action.lifecycle.Service;
Jonathan Hartbfc5c482016-04-05 18:57:00 -070024import org.onosproject.cli.AbstractShellCommand;
Ray Milkey69ec8712017-08-08 13:00:43 -070025import org.onosproject.routeservice.ResolvedRoute;
Seyeon Jeong357bcec2020-02-28 01:17:34 -080026import org.onosproject.routeservice.Route;
Ray Milkey69ec8712017-08-08 13:00:43 -070027import org.onosproject.routeservice.RouteInfo;
28import org.onosproject.routeservice.RouteService;
29import org.onosproject.routeservice.RouteTableId;
Jonathan Hartbfc5c482016-04-05 18:57:00 -070030
31import java.util.Collection;
Jonathan Hart96c146b2017-02-24 16:32:00 -080032import java.util.Comparator;
33import java.util.Objects;
34import java.util.Optional;
Jonathan Hartbfc5c482016-04-05 18:57:00 -070035
36/**
37 * Command to show the routes in the routing tables.
38 */
Ray Milkey7a2dee52018-09-28 10:58:28 -070039@Service
Jonathan Hart92ca5d32016-04-14 18:05:52 -070040@Command(scope = "onos", name = "routes",
Jonathan Hart96c146b2017-02-24 16:32:00 -080041 description = "Lists routes in the route store")
Jonathan Hartbfc5c482016-04-05 18:57:00 -070042public class RoutesListCommand extends AbstractShellCommand {
43
Charles Chan92ca94d2017-03-17 18:05:22 -070044 private static final String NETWORK = "Network";
45 private static final String NEXTHOP = "Next Hop";
46 private static final String SOURCE = "Source";
Jonathan Hart10dbafd2017-05-18 15:53:03 -070047 private static final String NODE = "Node";
Charles Chan92ca94d2017-03-17 18:05:22 -070048
Charles Chan32a31aa2018-04-11 11:10:42 -040049 private static final String FORMAT_ROUTE = "%-1s %-1s %-18s %-15s %s (%s)";
50 private static final String FORMAT_ROUTE6 = "%-1s %-1s %-43s %-39s %s (%s)";
Jonathan Hartbfc5c482016-04-05 18:57:00 -070051
52 private static final String FORMAT_TABLE = "Table: %s";
53 private static final String FORMAT_TOTAL = " Total: %d";
54
55 @Override
Ray Milkey86ad7bb2018-09-27 12:32:28 -070056 protected void doExecute() {
Jonathan Hartbfc5c482016-04-05 18:57:00 -070057 RouteService service = AbstractShellCommand.get(RouteService.class);
58
Jonathan Hartb2111342016-04-20 16:57:37 -070059 if (outputJson()) {
60 ObjectMapper mapper = new ObjectMapper();
61 ObjectNode result = mapper.createObjectNode();
Jonathan Hart96c146b2017-02-24 16:32:00 -080062 result.set("routes4", json(service.getRoutes(new RouteTableId("ipv4"))));
63 result.set("routes6", json(service.getRoutes(new RouteTableId("ipv6"))));
Jonathan Hartb2111342016-04-20 16:57:37 -070064 print("%s", result);
65 } else {
Charles Chan32a31aa2018-04-11 11:10:42 -040066 print("B: Best route, R: Resolved route\n");
Jonathan Hart96c146b2017-02-24 16:32:00 -080067 service.getRouteTables().forEach(id -> {
Jonathan Hart96c146b2017-02-24 16:32:00 -080068 Collection<RouteInfo> tableRoutes = service.getRoutes(id);
69
Charles Chan92ca94d2017-03-17 18:05:22 -070070 String format = tableRoutes.stream().anyMatch(route -> route.prefix().isIp6()) ?
71 FORMAT_ROUTE6 : FORMAT_ROUTE;
72
73 // Print header
74 print(FORMAT_TABLE, id);
Charles Chan32a31aa2018-04-11 11:10:42 -040075 print(format, "B", "R", NETWORK, NEXTHOP, SOURCE, NODE);
Charles Chan92ca94d2017-03-17 18:05:22 -070076
77 // Print routing entries
Jonathan Hart96c146b2017-02-24 16:32:00 -080078 tableRoutes.stream()
79 .sorted(Comparator.comparing(r -> r.prefix().address()))
Charles Chan92ca94d2017-03-17 18:05:22 -070080 .forEach(route -> this.print(format, route));
Jonathan Hart96c146b2017-02-24 16:32:00 -080081
82 print(FORMAT_TOTAL, tableRoutes.size());
Jonathan Hartb2111342016-04-20 16:57:37 -070083 print("");
84 });
85 }
Jonathan Hart96c146b2017-02-24 16:32:00 -080086 }
Jonathan Hartbfc5c482016-04-05 18:57:00 -070087
Charles Chan92ca94d2017-03-17 18:05:22 -070088 private void print(String format, RouteInfo routeInfo) {
Jonathan Hart58ea8f22017-05-08 15:09:31 -070089 routeInfo.allRoutes().stream()
Charles Chan32a31aa2018-04-11 11:10:42 -040090 .sorted(Comparator.comparing(ResolvedRoute::nextHop))
91 .forEach(r -> print(format,
92 isBestRoute(routeInfo.bestRoute(), r) ? ">" : "",
93 isResolvedRoute(r) ? "*" : "",
Jonathan Hart10dbafd2017-05-18 15:53:03 -070094 r.prefix(), r.nextHop(), r.route().source(), r.route().sourceNode()));
Jonathan Hart96c146b2017-02-24 16:32:00 -080095 }
96
Jonathan Hart96c146b2017-02-24 16:32:00 -080097 private boolean isBestRoute(Optional<ResolvedRoute> bestRoute, ResolvedRoute route) {
98 return Objects.equals(bestRoute.orElse(null), route);
Jonathan Hartbfc5c482016-04-05 18:57:00 -070099 }
100
Charles Chan32a31aa2018-04-11 11:10:42 -0400101 private boolean isResolvedRoute(ResolvedRoute route) {
102 return route.nextHopMac() != null && route.nextHopVlan() != null;
103 }
104
Jonathan Hartb2111342016-04-20 16:57:37 -0700105 /**
106 * Produces a JSON array of routes.
107 *
108 * @param routes the routes with the data
109 * @return JSON array with the routes
110 */
Jonathan Hart96c146b2017-02-24 16:32:00 -0800111 private JsonNode json(Collection<RouteInfo> routes) {
Jonathan Hartb2111342016-04-20 16:57:37 -0700112 ObjectMapper mapper = new ObjectMapper();
113 ArrayNode result = mapper.createArrayNode();
114
Jonathan Hart96c146b2017-02-24 16:32:00 -0800115 routes.stream()
116 .flatMap(ri -> ri.allRoutes().stream())
Seyeon Jeong357bcec2020-02-28 01:17:34 -0800117 .forEach(r -> {
118 // use RouteCodec to encode the Route object inside ResolvedRoute
119 ObjectNode routeNode = jsonForEntity(r.route(), Route.class);
120 if (r.nextHopMac() != null) {
121 routeNode.put("nextHopMac", r.nextHopMac().toString());
122 }
123 if (r.nextHopVlan() != null) {
124 routeNode.put("nextHopVlan", r.nextHopVlan().toString());
125 }
126 result.add(routeNode);
127 });
Jonathan Hartb2111342016-04-20 16:57:37 -0700128
129 return result;
130 }
131
Jonathan Hartbfc5c482016-04-05 18:57:00 -0700132}