820bb40ac36ccb08f038a68a76af0b05c531c572
[onosfw.git] /
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.segmentrouting;
17
18 import org.onosproject.net.DeviceId;
19 import org.onosproject.net.Link;
20 import org.onosproject.net.link.LinkService;
21 import org.onosproject.segmentrouting.grouphandler.DefaultGroupHandler;
22 import org.onosproject.segmentrouting.grouphandler.NeighborSet;
23 import org.onosproject.store.service.EventuallyConsistentMap;
24 import org.slf4j.Logger;
25
26 import java.util.ArrayList;
27 import java.util.HashSet;
28 import java.util.List;
29 import java.util.Map;
30 import java.util.Set;
31
32 import static org.slf4j.LoggerFactory.getLogger;
33
34 /**
35  * Tunnel Handler.
36  */
37 public class TunnelHandler {
38     protected final Logger log = getLogger(getClass());
39
40     private final DeviceConfiguration config;
41     private final EventuallyConsistentMap<String, Tunnel> tunnelStore;
42     private Map<DeviceId, DefaultGroupHandler> groupHandlerMap;
43     private LinkService linkService;
44
45     public enum Result {
46         SUCCESS,
47         WRONG_PATH,
48         TUNNEL_EXISTS,
49         ID_EXISTS,
50         TUNNEL_NOT_FOUND,
51         TUNNEL_IN_USE,
52         INTERNAL_ERROR
53     }
54
55     public TunnelHandler(LinkService linkService,
56                          DeviceConfiguration deviceConfiguration,
57                          Map<DeviceId, DefaultGroupHandler> groupHandlerMap,
58                          EventuallyConsistentMap<String, Tunnel> tunnelStore) {
59         this.linkService = linkService;
60         this.config = deviceConfiguration;
61         this.groupHandlerMap = groupHandlerMap;
62         this.tunnelStore = tunnelStore;
63     }
64
65     /**
66      * Creates a tunnel.
67      *
68      * @param tunnel tunnel reference to create a tunnel
69      * @return WRONG_PATH if the tunnel path is wrong, ID_EXISTS if the tunnel ID
70      * exists already, TUNNEL_EXISTS if the same tunnel exists, INTERNAL_ERROR
71      * if the tunnel creation failed internally, SUCCESS if the tunnel is created
72      * successfully
73      */
74     public Result createTunnel(Tunnel tunnel) {
75
76         if (tunnel.labelIds().isEmpty() || tunnel.labelIds().size() < 3) {
77             log.error("More than one router needs to specified to created a tunnel");
78             return Result.WRONG_PATH;
79         }
80
81         if (tunnelStore.containsKey(tunnel.id())) {
82             log.warn("The same tunnel ID exists already");
83             return Result.ID_EXISTS;
84         }
85
86         if (tunnelStore.containsValue(tunnel)) {
87             log.warn("The same tunnel exists already");
88             return Result.TUNNEL_EXISTS;
89         }
90
91         int groupId = createGroupsForTunnel(tunnel);
92         if (groupId < 0) {
93             log.error("Failed to create groups for the tunnel");
94             return Result.INTERNAL_ERROR;
95         }
96
97         tunnel.setGroupId(groupId);
98         tunnelStore.put(tunnel.id(), tunnel);
99
100         return Result.SUCCESS;
101     }
102
103     /**
104      * Removes the tunnel with the tunnel ID given.
105      *
106      * @param tunnelInfo tunnel information to delete tunnels
107      * @return TUNNEL_NOT_FOUND if the tunnel to remove does not exists,
108      * INTERNAL_ERROR if the tunnel creation failed internally, SUCCESS
109      * if the tunnel is created successfully.
110      */
111     public Result removeTunnel(Tunnel tunnelInfo) {
112
113         Tunnel tunnel = tunnelStore.get(tunnelInfo.id());
114         if (tunnel != null) {
115             DeviceId deviceId = config.getDeviceId(tunnel.labelIds().get(0));
116             if (tunnel.isAllowedToRemoveGroup()) {
117                 if (groupHandlerMap.get(deviceId).removeGroup(tunnel.groupId())) {
118                     tunnelStore.remove(tunnel.id());
119                 } else {
120                     log.error("Failed to remove the tunnel {}", tunnelInfo.id());
121                     return Result.INTERNAL_ERROR;
122                 }
123             } else {
124                 log.debug("The group is not removed because it is being used.");
125                 tunnelStore.remove(tunnel.id());
126             }
127         } else {
128             log.error("No tunnel found for tunnel ID {}", tunnelInfo.id());
129             return Result.TUNNEL_NOT_FOUND;
130         }
131
132         return Result.SUCCESS;
133     }
134
135     /**
136      * Returns the tunnel with the tunnel ID given.
137      *
138      * @param tid Tunnel ID
139      * @return Tunnel reference
140      */
141     public Tunnel getTunnel(String tid) {
142         return tunnelStore.get(tid);
143     }
144
145     /**
146      * Returns all tunnels.
147      *
148      * @return list of Tunnels
149      */
150     public List<Tunnel> getTunnels() {
151         List<Tunnel> tunnels = new ArrayList<>();
152         tunnelStore.values().forEach(tunnel -> tunnels.add(
153                 new DefaultTunnel((DefaultTunnel) tunnel)));
154
155         return tunnels;
156     }
157
158     private int createGroupsForTunnel(Tunnel tunnel) {
159
160         List<Integer> portNumbers;
161         final int groupError = -1;
162
163         DeviceId deviceId = config.getDeviceId(tunnel.labelIds().get(0));
164         if (deviceId == null) {
165             log.warn("No device found for SID {}", tunnel.labelIds().get(0));
166             return groupError;
167         } else if (groupHandlerMap.get(deviceId) == null) {
168             log.warn("group handler not found for {}", deviceId);
169             return groupError;
170         }
171         Set<DeviceId> deviceIds = new HashSet<>();
172         int sid = tunnel.labelIds().get(1);
173         if (config.isAdjacencySid(deviceId, sid)) {
174             portNumbers = config.getPortsForAdjacencySid(deviceId, sid);
175             for (Link link: linkService.getDeviceEgressLinks(deviceId)) {
176                 for (Integer port: portNumbers) {
177                     if (link.src().port().toLong() == port) {
178                         deviceIds.add(link.dst().deviceId());
179                     }
180                 }
181             }
182         } else {
183             deviceIds.add(config.getDeviceId(sid));
184         }
185
186         NeighborSet ns = new NeighborSet(deviceIds, tunnel.labelIds().get(2));
187
188         // If the tunnel reuses any existing groups, then tunnel handler
189         // should not remove the group.
190         if (groupHandlerMap.get(deviceId).hasNextObjectiveId(ns)) {
191             tunnel.allowToRemoveGroup(false);
192         } else {
193             tunnel.allowToRemoveGroup(true);
194         }
195
196         return groupHandlerMap.get(deviceId).getNextObjectiveId(ns);
197     }
198
199 }