blob: c3ecfb98b7e92f79392b4700b69528cd22839b0f [file] [log] [blame]
sangho80f11cb2015-04-01 13:05:26 -07001/*
Brian O'Connor0947d7e2017-08-03 21:12:30 -07002 * Copyright 2015-present Open Networking Foundation
sangho80f11cb2015-04-01 13:05:26 -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 */
16package org.onosproject.segmentrouting;
17
Pier Ventre229fd0b2016-10-31 16:49:19 -070018import com.google.common.collect.Lists;
Charles Chan051490d2018-01-11 11:48:18 -080019import com.google.common.collect.Sets;
Charles Chan61c086d2019-07-26 17:46:15 -070020import org.apache.commons.lang3.tuple.ImmutablePair;
Saurav Das4c35fc42015-11-20 15:27:53 -080021import org.onlab.packet.EthType;
sangho80f11cb2015-04-01 13:05:26 -070022import org.onlab.packet.Ethernet;
Charles Chanef8d12e2017-12-05 21:07:38 -080023import org.onlab.packet.IPv6;
sangho80f11cb2015-04-01 13:05:26 -070024import org.onlab.packet.Ip4Address;
Pier Ventreadb4ae62016-11-23 09:57:42 -080025import org.onlab.packet.Ip6Address;
26import org.onlab.packet.IpAddress;
sangho80f11cb2015-04-01 13:05:26 -070027import org.onlab.packet.IpPrefix;
28import org.onlab.packet.MacAddress;
sangho80f11cb2015-04-01 13:05:26 -070029import org.onlab.packet.MplsLabel;
Srikanth Vavilapalli64505482015-04-21 13:04:13 -070030import org.onlab.packet.VlanId;
Charles Chanb7f75ac2016-01-11 18:28:54 -080031import org.onosproject.net.ConnectPoint;
Saurav Das9bf49582018-08-13 15:34:26 -070032import org.onosproject.net.Device;
Charles Chanf17fade2020-03-08 18:07:19 -070033import org.onosproject.net.Host;
Charles Chan1eaf4802016-04-18 13:44:03 -070034import org.onosproject.net.flowobjective.DefaultObjectiveContext;
Pier Luigib9632ba2017-01-12 18:14:58 -080035import org.onosproject.net.flowobjective.Objective;
Charles Chan1eaf4802016-04-18 13:44:03 -070036import org.onosproject.net.flowobjective.ObjectiveContext;
Pier Luigib9632ba2017-01-12 18:14:58 -080037import org.onosproject.net.flowobjective.ObjectiveError;
Jonghwan Hyun671a7ab2018-04-30 09:27:21 -070038import org.onosproject.net.intf.Interface;
Charles Chan2d0bbcd2017-01-09 11:45:08 -080039import org.onosproject.net.packet.PacketPriority;
Charles Chan319d1a22015-11-03 10:42:14 -080040import org.onosproject.segmentrouting.config.DeviceConfigNotFoundException;
Saurav Das62ae6792017-05-15 15:34:25 -070041import org.onosproject.segmentrouting.grouphandler.DefaultGroupHandler;
Saurav Das261c3002017-06-13 15:35:54 -070042import org.onosproject.segmentrouting.grouphandler.DestinationSet;
sangho80f11cb2015-04-01 13:05:26 -070043import org.onosproject.net.DeviceId;
Saurav Das7c305372015-10-28 12:39:42 -070044import org.onosproject.net.Port;
sangho80f11cb2015-04-01 13:05:26 -070045import org.onosproject.net.PortNumber;
sangho80f11cb2015-04-01 13:05:26 -070046import org.onosproject.net.flow.DefaultTrafficSelector;
47import org.onosproject.net.flow.DefaultTrafficTreatment;
sangho80f11cb2015-04-01 13:05:26 -070048import org.onosproject.net.flow.TrafficSelector;
49import org.onosproject.net.flow.TrafficTreatment;
Srikanth Vavilapalli64505482015-04-21 13:04:13 -070050import org.onosproject.net.flow.criteria.Criteria;
51import org.onosproject.net.flowobjective.DefaultFilteringObjective;
52import org.onosproject.net.flowobjective.DefaultForwardingObjective;
53import org.onosproject.net.flowobjective.FilteringObjective;
54import org.onosproject.net.flowobjective.ForwardingObjective;
55import org.onosproject.net.flowobjective.ForwardingObjective.Builder;
Saurav Das9f1c42e2015-10-23 10:51:11 -070056import org.onosproject.net.flowobjective.ForwardingObjective.Flag;
sangho80f11cb2015-04-01 13:05:26 -070057import org.slf4j.Logger;
58import org.slf4j.LoggerFactory;
59
60import java.util.ArrayList;
Pier Ventre229fd0b2016-10-31 16:49:19 -070061import java.util.Collection;
62import java.util.Collections;
Saurav Das261c3002017-06-13 15:35:54 -070063import java.util.HashMap;
Saurav Dasc28b3432015-10-30 17:45:38 -070064import java.util.HashSet;
sangho80f11cb2015-04-01 13:05:26 -070065import java.util.List;
Saurav Das261c3002017-06-13 15:35:54 -070066import java.util.Map;
Charles Chan2d0bbcd2017-01-09 11:45:08 -080067import java.util.Optional;
sangho80f11cb2015-04-01 13:05:26 -070068import java.util.Set;
Charles Chan12a8a842020-02-14 13:23:57 -080069import java.util.concurrent.CompletableFuture;
sanghofb7c7292015-04-13 15:15:58 -070070import java.util.concurrent.atomic.AtomicLong;
Charles Chanf17f66b2018-02-26 21:33:25 -080071import java.util.stream.Collectors;
sangho80f11cb2015-04-01 13:05:26 -070072
73import static com.google.common.base.Preconditions.checkNotNull;
Pier Luigib9632ba2017-01-12 18:14:58 -080074import static org.onlab.packet.Ethernet.TYPE_ARP;
75import static org.onlab.packet.Ethernet.TYPE_IPV6;
Charles Chan051490d2018-01-11 11:48:18 -080076import static org.onlab.packet.ICMP6.NEIGHBOR_ADVERTISEMENT;
Pier Luigib9632ba2017-01-12 18:14:58 -080077import static org.onlab.packet.ICMP6.NEIGHBOR_SOLICITATION;
Charles Chan051490d2018-01-11 11:48:18 -080078import static org.onlab.packet.ICMP6.ROUTER_ADVERTISEMENT;
79import static org.onlab.packet.ICMP6.ROUTER_SOLICITATION;
Pier Luigib9632ba2017-01-12 18:14:58 -080080import static org.onlab.packet.IPv6.PROTOCOL_ICMP6;
Jonghwan Hyun9aaa34f2018-04-09 09:40:50 -070081import static org.onosproject.segmentrouting.SegmentRoutingService.DEFAULT_PRIORITY;
sangho80f11cb2015-04-01 13:05:26 -070082
Charles Chanb7f75ac2016-01-11 18:28:54 -080083/**
84 * Populator of segment routing flow rules.
85 */
sangho80f11cb2015-04-01 13:05:26 -070086public class RoutingRulePopulator {
Charles Chanef8d12e2017-12-05 21:07:38 -080087 private static final Logger log = LoggerFactory.getLogger(RoutingRulePopulator.class);
88
89 private static final int ARP_NDP_PRIORITY = 30000;
sangho80f11cb2015-04-01 13:05:26 -070090
sanghofb7c7292015-04-13 15:15:58 -070091 private AtomicLong rulePopulationCounter;
sangho9b169e32015-04-14 16:27:13 -070092 private SegmentRoutingManager srManager;
93 private DeviceConfiguration config;
psneha86e60d32019-03-26 06:31:41 -040094 private RouteSimplifierUtils routeSimplifierUtils;
Saurav Das9f1c42e2015-10-23 10:51:11 -070095
Andreas Pantelopoulos59bd97e2018-06-28 17:06:14 -070096 // used for signalling the driver to remove vlan table and tmac entry also
97 private static final long CLEANUP_DOUBLE_TAGGED_HOST_ENTRIES = 1;
98 private static final long DOUBLE_TAGGED_METADATA_MASK = 0xffffffffffffffffL;
99
sangho80f11cb2015-04-01 13:05:26 -0700100 /**
101 * Creates a RoutingRulePopulator object.
102 *
Thomas Vachuska8a075092015-04-15 18:20:08 -0700103 * @param srManager segment routing manager reference
sangho80f11cb2015-04-01 13:05:26 -0700104 */
Charles Chan3ed34d82017-06-22 18:03:14 -0700105 RoutingRulePopulator(SegmentRoutingManager srManager) {
sangho80f11cb2015-04-01 13:05:26 -0700106 this.srManager = srManager;
sangho9b169e32015-04-14 16:27:13 -0700107 this.config = checkNotNull(srManager.deviceConfiguration);
sanghofb7c7292015-04-13 15:15:58 -0700108 this.rulePopulationCounter = new AtomicLong(0);
psneha86e60d32019-03-26 06:31:41 -0400109 this.routeSimplifierUtils = new RouteSimplifierUtils(srManager);
sanghofb7c7292015-04-13 15:15:58 -0700110 }
111
112 /**
113 * Resets the population counter.
114 */
Charles Chan3ed34d82017-06-22 18:03:14 -0700115 void resetCounter() {
sanghofb7c7292015-04-13 15:15:58 -0700116 rulePopulationCounter.set(0);
117 }
118
119 /**
120 * Returns the number of rules populated.
Thomas Vachuska7cfc6202015-04-30 18:13:25 -0700121 *
122 * @return number of rules
sanghofb7c7292015-04-13 15:15:58 -0700123 */
Charles Chan3ed34d82017-06-22 18:03:14 -0700124 long getCounter() {
sanghofb7c7292015-04-13 15:15:58 -0700125 return rulePopulationCounter.get();
sangho80f11cb2015-04-01 13:05:26 -0700126 }
127
128 /**
Charles Chand66d6712018-03-29 16:03:41 -0700129 * Populate a bridging rule on given deviceId that matches given mac, given vlan and
130 * output to given port.
131 *
132 * @param deviceId device ID
133 * @param port port
134 * @param mac mac address
135 * @param vlanId VLAN ID
Charles Chan12a8a842020-02-14 13:23:57 -0800136 * @return future that carries the flow objective if succeeded, null if otherwise
Charles Chand66d6712018-03-29 16:03:41 -0700137 */
Charles Chan12a8a842020-02-14 13:23:57 -0800138 CompletableFuture<Objective> populateBridging(DeviceId deviceId, PortNumber port, MacAddress mac, VlanId vlanId) {
Charles Chand66d6712018-03-29 16:03:41 -0700139 ForwardingObjective.Builder fob = bridgingFwdObjBuilder(deviceId, mac, vlanId, port, false);
140 if (fob == null) {
141 log.warn("Fail to build fwd obj for host {}/{}. Abort.", mac, vlanId);
Charles Chan12a8a842020-02-14 13:23:57 -0800142 return CompletableFuture.completedFuture(null);
Charles Chand66d6712018-03-29 16:03:41 -0700143 }
144
Charles Chan12a8a842020-02-14 13:23:57 -0800145 CompletableFuture<Objective> future = new CompletableFuture<>();
Charles Chand66d6712018-03-29 16:03:41 -0700146 ObjectiveContext context = new DefaultObjectiveContext(
Charles Chan12a8a842020-02-14 13:23:57 -0800147 (objective) -> {
148 log.debug("Brigding rule for {}/{} populated", mac, vlanId);
149 future.complete(objective);
150 },
151 (objective, error) -> {
152 log.warn("Failed to populate bridging rule for {}/{}: {}", mac, vlanId, error);
153 future.complete(null);
154 });
Charles Chand66d6712018-03-29 16:03:41 -0700155 srManager.flowObjectiveService.forward(deviceId, fob.add(context));
Charles Chan12a8a842020-02-14 13:23:57 -0800156 return future;
Charles Chand66d6712018-03-29 16:03:41 -0700157 }
158
159 /**
160 * Revoke a bridging rule on given deviceId that matches given mac, given vlan and
161 * output to given port.
162 *
163 * @param deviceId device ID
164 * @param port port
165 * @param mac mac address
166 * @param vlanId VLAN ID
Charles Chan12a8a842020-02-14 13:23:57 -0800167 * @return future that carries the flow objective if succeeded, null if otherwise
Charles Chand66d6712018-03-29 16:03:41 -0700168 */
Charles Chan12a8a842020-02-14 13:23:57 -0800169 CompletableFuture<Objective> revokeBridging(DeviceId deviceId, PortNumber port, MacAddress mac, VlanId vlanId) {
Charles Chand66d6712018-03-29 16:03:41 -0700170 ForwardingObjective.Builder fob = bridgingFwdObjBuilder(deviceId, mac, vlanId, port, true);
171 if (fob == null) {
172 log.warn("Fail to build fwd obj for host {}/{}. Abort.", mac, vlanId);
Charles Chan12a8a842020-02-14 13:23:57 -0800173 return CompletableFuture.completedFuture(null);
Charles Chand66d6712018-03-29 16:03:41 -0700174 }
175
Charles Chan12a8a842020-02-14 13:23:57 -0800176 CompletableFuture<Objective> future = new CompletableFuture<>();
Charles Chand66d6712018-03-29 16:03:41 -0700177 ObjectiveContext context = new DefaultObjectiveContext(
Charles Chan12a8a842020-02-14 13:23:57 -0800178 (objective) -> {
179 log.debug("Brigding rule for {}/{} revoked", mac, vlanId);
180 future.complete(objective);
181 },
182 (objective, error) -> {
183 log.warn("Failed to revoke bridging rule for {}/{}: {}", mac, vlanId, error);
184 future.complete(null);
185 });
Charles Chand66d6712018-03-29 16:03:41 -0700186 srManager.flowObjectiveService.forward(deviceId, fob.remove(context));
Charles Chan12a8a842020-02-14 13:23:57 -0800187 return future;
Charles Chand66d6712018-03-29 16:03:41 -0700188 }
189
190 /**
191 * Generates a forwarding objective builder for bridging rules.
192 * <p>
193 * The forwarding objective bridges packets destined to a given MAC to
194 * given port on given device.
195 *
196 * @param deviceId Device that host attaches to
197 * @param mac MAC address of the host
198 * @param hostVlanId VLAN ID of the host
199 * @param outport Port that host attaches to
200 * @param revoke true if forwarding objective is meant to revoke forwarding rule
201 * @return Forwarding objective builder
202 */
203 private ForwardingObjective.Builder bridgingFwdObjBuilder(
204 DeviceId deviceId, MacAddress mac, VlanId hostVlanId, PortNumber outport, boolean revoke) {
205 ConnectPoint connectPoint = new ConnectPoint(deviceId, outport);
Charles Chan098ca202018-05-01 11:50:20 -0700206 VlanId untaggedVlan = srManager.interfaceService.getUntaggedVlanId(connectPoint);
207 Set<VlanId> taggedVlans = srManager.interfaceService.getTaggedVlanId(connectPoint);
208 VlanId nativeVlan = srManager.interfaceService.getNativeVlanId(connectPoint);
Charles Chand66d6712018-03-29 16:03:41 -0700209
210 // Create host selector
211 TrafficSelector.Builder sbuilder = DefaultTrafficSelector.builder();
212 sbuilder.matchEthDst(mac);
213
214 // Create host treatment
215 TrafficTreatment.Builder tbuilder = DefaultTrafficTreatment.builder();
216 tbuilder.immediate().setOutput(outport);
217
218 // Create host meta
219 TrafficSelector.Builder mbuilder = DefaultTrafficSelector.builder();
220
221 // Adjust the selector, treatment and meta according to VLAN configuration
222 if (taggedVlans.contains(hostVlanId)) {
223 sbuilder.matchVlanId(hostVlanId);
224 mbuilder.matchVlanId(hostVlanId);
225 } else if (hostVlanId.equals(VlanId.NONE)) {
226 if (untaggedVlan != null) {
227 sbuilder.matchVlanId(untaggedVlan);
228 mbuilder.matchVlanId(untaggedVlan);
229 tbuilder.immediate().popVlan();
230 } else if (nativeVlan != null) {
231 sbuilder.matchVlanId(nativeVlan);
232 mbuilder.matchVlanId(nativeVlan);
233 tbuilder.immediate().popVlan();
234 } else {
235 log.warn("Untagged host {}/{} is not allowed on {} without untagged or native" +
236 "vlan config", mac, hostVlanId, connectPoint);
237 return null;
238 }
239 } else {
240 log.warn("Tagged host {}/{} is not allowed on {} without VLAN listed in tagged vlan",
241 mac, hostVlanId, connectPoint);
242 return null;
243 }
244
245 // All forwarding is via Groups. Drivers can re-purpose to flow-actions if needed.
246 // If the objective is to revoke an existing rule, and for some reason
247 // the next-objective does not exist, then a new one should not be created
248 int portNextObjId = srManager.getPortNextObjectiveId(deviceId, outport,
249 tbuilder.build(), mbuilder.build(), !revoke);
250 if (portNextObjId == -1) {
251 // Warning log will come from getPortNextObjective method
252 return null;
253 }
254
255 return DefaultForwardingObjective.builder()
256 .withFlag(ForwardingObjective.Flag.SPECIFIC)
257 .withSelector(sbuilder.build())
258 .nextStep(portNextObjId)
259 .withPriority(100)
260 .fromApp(srManager.appId)
261 .makePermanent();
262 }
263
264 /**
265 * Populate or revoke a bridging rule on given deviceId that matches given vlanId,
266 * and hostMAC connected to given port, and output to given port only when
267 * vlan information is valid.
268 *
269 * @param deviceId device ID that host attaches to
270 * @param portNum port number that host attaches to
271 * @param hostMac mac address of the host connected to the switch port
272 * @param vlanId Vlan ID configured on the switch port
273 * @param popVlan true to pop Vlan tag at TrafficTreatment, false otherwise
274 * @param install true to populate the objective, false to revoke
275 */
276 // TODO Refactor. There are a lot of duplications between this method, populateBridging,
277 // revokeBridging and bridgingFwdObjBuilder.
278 void updateBridging(DeviceId deviceId, PortNumber portNum, MacAddress hostMac,
279 VlanId vlanId, boolean popVlan, boolean install) {
280 // Create host selector
281 TrafficSelector.Builder sbuilder = DefaultTrafficSelector.builder();
282 sbuilder.matchEthDst(hostMac);
283
284 // Create host meta
285 TrafficSelector.Builder mbuilder = DefaultTrafficSelector.builder();
286
287 sbuilder.matchVlanId(vlanId);
288 mbuilder.matchVlanId(vlanId);
289
290 // Create host treatment
291 TrafficTreatment.Builder tbuilder = DefaultTrafficTreatment.builder();
292 tbuilder.immediate().setOutput(portNum);
293
294 if (popVlan) {
295 tbuilder.immediate().popVlan();
296 }
297
298 int portNextObjId = srManager.getPortNextObjectiveId(deviceId, portNum,
299 tbuilder.build(), mbuilder.build(), install);
300 if (portNextObjId != -1) {
301 ForwardingObjective.Builder fob = DefaultForwardingObjective.builder()
302 .withFlag(ForwardingObjective.Flag.SPECIFIC)
303 .withSelector(sbuilder.build())
304 .nextStep(portNextObjId)
305 .withPriority(100)
306 .fromApp(srManager.appId)
307 .makePermanent();
308
309 ObjectiveContext context = new DefaultObjectiveContext(
310 (objective) -> log.debug("Brigding rule for {}/{} {}", hostMac, vlanId,
311 install ? "populated" : "revoked"),
312 (objective, error) -> log.warn("Failed to {} bridging rule for {}/{}: {}",
313 install ? "populate" : "revoke", hostMac, vlanId, error));
314 srManager.flowObjectiveService.forward(deviceId, install ? fob.add(context) : fob.remove(context));
315 } else {
316 log.warn("Failed to retrieve next objective for {}/{}", hostMac, vlanId);
317 }
318 }
319
320 /**
321 * Populates IP rules for a route that has direct connection to the switch.
322 * This method should not be invoked directly without going through DefaultRoutingHandler.
sangho80f11cb2015-04-01 13:05:26 -0700323 *
Charles Chanddac7fd2016-10-27 14:19:48 -0700324 * @param deviceId device ID of the device that next hop attaches to
325 * @param prefix IP prefix of the route
326 * @param hostMac MAC address of the next hop
Charles Chan90772a72017-02-08 15:52:08 -0800327 * @param hostVlanId Vlan ID of the nexthop
Charles Chanddac7fd2016-10-27 14:19:48 -0700328 * @param outPort port where the next hop attaches to
Ruchi Sahota71bcb4e2019-01-28 01:08:18 +0000329 * @param directHost host is of type direct or indirect
Charles Chan12a8a842020-02-14 13:23:57 -0800330 * @return future that carries the flow objective if succeeded, null if otherwise
sangho80f11cb2015-04-01 13:05:26 -0700331 */
Charles Chan12a8a842020-02-14 13:23:57 -0800332 CompletableFuture<Objective> populateRoute(DeviceId deviceId, IpPrefix prefix,
Ruchi Sahota71bcb4e2019-01-28 01:08:18 +0000333 MacAddress hostMac, VlanId hostVlanId, PortNumber outPort, boolean directHost) {
Saurav Das261c3002017-06-13 15:35:54 -0700334 log.debug("Populate direct routing entry for route {} at {}:{}",
Charles Chanddac7fd2016-10-27 14:19:48 -0700335 prefix, deviceId, outPort);
Charles Chanf4586112015-11-09 16:37:23 -0800336 ForwardingObjective.Builder fwdBuilder;
Charles Chan319d1a22015-11-03 10:42:14 -0800337 try {
Saurav Das2cb38292017-03-29 19:09:17 -0700338 fwdBuilder = routingFwdObjBuilder(deviceId, prefix, hostMac,
Charles Chan61c086d2019-07-26 17:46:15 -0700339 hostVlanId, outPort, null, null, directHost, false);
Charles Chan319d1a22015-11-03 10:42:14 -0800340 } catch (DeviceConfigNotFoundException e) {
Saurav Das261c3002017-06-13 15:35:54 -0700341 log.warn(e.getMessage() + " Aborting direct populateRoute");
Charles Chan12a8a842020-02-14 13:23:57 -0800342 return CompletableFuture.completedFuture(null);
Charles Chan319d1a22015-11-03 10:42:14 -0800343 }
Saurav Das07c74602016-04-27 18:35:50 -0700344 if (fwdBuilder == null) {
Saurav Das368cf212017-03-15 15:15:14 -0700345 log.warn("Aborting host routing table entry due "
Charles Chanddac7fd2016-10-27 14:19:48 -0700346 + "to error for dev:{} route:{}", deviceId, prefix);
Charles Chan12a8a842020-02-14 13:23:57 -0800347 return CompletableFuture.completedFuture(null);
Saurav Das07c74602016-04-27 18:35:50 -0700348 }
Charles Chan910be6a2017-08-23 14:46:43 -0700349
350 int nextId = fwdBuilder.add().nextId();
Charles Chan12a8a842020-02-14 13:23:57 -0800351 CompletableFuture<Objective> future = new CompletableFuture<>();
Charles Chan1eaf4802016-04-18 13:44:03 -0700352 ObjectiveContext context = new DefaultObjectiveContext(
Charles Chan12a8a842020-02-14 13:23:57 -0800353 (objective) -> {
354 log.debug("Direct routing rule for route {} populated. nextId={}", prefix, nextId);
355 future.complete(objective);
356 },
357 (objective, error) -> {
358 log.warn("Failed to populate direct routing rule for route {}: {}", prefix, error);
359 future.complete(null);
360 });
Charles Chan1eaf4802016-04-18 13:44:03 -0700361 srManager.flowObjectiveService.forward(deviceId, fwdBuilder.add(context));
Charles Chanf4586112015-11-09 16:37:23 -0800362 rulePopulationCounter.incrementAndGet();
Charles Chan12a8a842020-02-14 13:23:57 -0800363 return future;
Charles Chanf4586112015-11-09 16:37:23 -0800364 }
365
Charles Chanb7f75ac2016-01-11 18:28:54 -0800366 /**
Charles Chanddac7fd2016-10-27 14:19:48 -0700367 * Removes IP rules for a route when the next hop is gone.
Charles Chand66d6712018-03-29 16:03:41 -0700368 * This method should not be invoked directly without going through DefaultRoutingHandler.
Charles Chanb7f75ac2016-01-11 18:28:54 -0800369 *
Charles Chanddac7fd2016-10-27 14:19:48 -0700370 * @param deviceId device ID of the device that next hop attaches to
371 * @param prefix IP prefix of the route
372 * @param hostMac MAC address of the next hop
Charles Chan90772a72017-02-08 15:52:08 -0800373 * @param hostVlanId Vlan ID of the nexthop
Charles Chanddac7fd2016-10-27 14:19:48 -0700374 * @param outPort port that next hop attaches to
Ruchi Sahota71bcb4e2019-01-28 01:08:18 +0000375 * @param directHost host is of type direct or indirect
Charles Chan12a8a842020-02-14 13:23:57 -0800376 * @return future that carries the flow objective if succeeded, null if otherwise
Charles Chanb7f75ac2016-01-11 18:28:54 -0800377 */
Charles Chan12a8a842020-02-14 13:23:57 -0800378 CompletableFuture<Objective> revokeRoute(DeviceId deviceId, IpPrefix prefix,
Ruchi Sahota71bcb4e2019-01-28 01:08:18 +0000379 MacAddress hostMac, VlanId hostVlanId, PortNumber outPort, boolean directHost) {
Charles Chanddac7fd2016-10-27 14:19:48 -0700380 log.debug("Revoke IP table entry for route {} at {}:{}",
381 prefix, deviceId, outPort);
Charles Chanf4586112015-11-09 16:37:23 -0800382 ForwardingObjective.Builder fwdBuilder;
383 try {
Saurav Das2cb38292017-03-29 19:09:17 -0700384 fwdBuilder = routingFwdObjBuilder(deviceId, prefix, hostMac,
Charles Chan61c086d2019-07-26 17:46:15 -0700385 hostVlanId, outPort, null, null, directHost, true);
Charles Chanf4586112015-11-09 16:37:23 -0800386 } catch (DeviceConfigNotFoundException e) {
387 log.warn(e.getMessage() + " Aborting revokeIpRuleForHost.");
Charles Chan12a8a842020-02-14 13:23:57 -0800388 return CompletableFuture.completedFuture(null);
Charles Chanf4586112015-11-09 16:37:23 -0800389 }
Charles Chanea702b12016-11-30 11:55:05 -0800390 if (fwdBuilder == null) {
391 log.warn("Aborting host routing table entries due "
392 + "to error for dev:{} route:{}", deviceId, prefix);
Charles Chan12a8a842020-02-14 13:23:57 -0800393 return CompletableFuture.completedFuture(null);
Charles Chanea702b12016-11-30 11:55:05 -0800394 }
Charles Chan12a8a842020-02-14 13:23:57 -0800395
396 CompletableFuture<Objective> future = new CompletableFuture<>();
Charles Chan1eaf4802016-04-18 13:44:03 -0700397 ObjectiveContext context = new DefaultObjectiveContext(
Charles Chan12a8a842020-02-14 13:23:57 -0800398 (objective) -> {
399 log.debug("IP rule for route {} revoked", prefix);
400 future.complete(objective);
401 },
402 (objective, error) -> {
403 log.warn("Failed to revoke IP rule for route {}: {}", prefix, error);
404 future.complete(null);
405 });
Charles Chan1eaf4802016-04-18 13:44:03 -0700406 srManager.flowObjectiveService.forward(deviceId, fwdBuilder.remove(context));
Charles Chan12a8a842020-02-14 13:23:57 -0800407 return future;
Charles Chanf4586112015-11-09 16:37:23 -0800408 }
409
Charles Chanddac7fd2016-10-27 14:19:48 -0700410 /**
Charles Chan18fa4252017-02-08 16:10:40 -0800411 * Returns a forwarding objective builder for routing rules.
412 * <p>
413 * The forwarding objective routes packets destined to a given prefix to
414 * given port on given device with given destination MAC.
Charles Chanddac7fd2016-10-27 14:19:48 -0700415 *
416 * @param deviceId device ID
417 * @param prefix prefix that need to be routed
418 * @param hostMac MAC address of the nexthop
Charles Chan90772a72017-02-08 15:52:08 -0800419 * @param hostVlanId Vlan ID of the nexthop
Charles Chanddac7fd2016-10-27 14:19:48 -0700420 * @param outPort port where the nexthop attaches to
Saurav Das2cb38292017-03-29 19:09:17 -0700421 * @param revoke true if forwarding objective is meant to revoke forwarding rule
Ruchi Sahota71bcb4e2019-01-28 01:08:18 +0000422 * @param directHost host is direct or indirect
Charles Chanddac7fd2016-10-27 14:19:48 -0700423 * @return forwarding objective builder
424 * @throws DeviceConfigNotFoundException if given device is not configured
425 */
Ruchi Sahota71bcb4e2019-01-28 01:08:18 +0000426
Charles Chan61c086d2019-07-26 17:46:15 -0700427 private ForwardingObjective.Builder routingFwdObjBuilder(
Charles Chanddac7fd2016-10-27 14:19:48 -0700428 DeviceId deviceId, IpPrefix prefix,
Saurav Das2cb38292017-03-29 19:09:17 -0700429 MacAddress hostMac, VlanId hostVlanId, PortNumber outPort,
Charles Chan61c086d2019-07-26 17:46:15 -0700430 VlanId innerVlan, EthType outerTpid,
Ruchi Sahota71bcb4e2019-01-28 01:08:18 +0000431 boolean directHost, boolean revoke)
Charles Chanf4586112015-11-09 16:37:23 -0800432 throws DeviceConfigNotFoundException {
Charles Chan61c086d2019-07-26 17:46:15 -0700433 int nextObjId;
434 if (directHost) {
435 // if the objective is to revoke an existing rule, and for some reason
436 // the next-objective does not exist, then a new one should not be created
437 ImmutablePair<TrafficTreatment, TrafficSelector> treatmentAndMeta =
438 getTreatmentAndMeta(deviceId, hostMac, hostVlanId, outPort, innerVlan, outerTpid);
439 if (treatmentAndMeta == null) {
440 // Warning log will come from getTreatmentAndMeta method
441 return null;
442 }
443 nextObjId = srManager.getPortNextObjectiveId(deviceId, outPort,
444 treatmentAndMeta.getLeft(), treatmentAndMeta.getRight(), !revoke);
445 } else {
446 // if the objective is to revoke an existing rule, and for some reason
447 // the next-objective does not exist, then a new one should not be created
448 nextObjId = srManager.getMacVlanNextObjectiveId(deviceId, hostMac, hostVlanId,
449 outPort, !revoke);
450 }
451 if (nextObjId == -1) {
452 // Warning log will come from getMacVlanNextObjective method
453 return null;
454 }
455
456 return DefaultForwardingObjective.builder()
457 .withSelector(buildIpSelectorFromIpPrefix(prefix).build())
458 .nextStep(nextObjId)
459 .fromApp(srManager.appId).makePermanent()
460 .withPriority(getPriorityFromPrefix(prefix))
461 .withFlag(ForwardingObjective.Flag.SPECIFIC);
462 }
463
464 private ImmutablePair<TrafficTreatment, TrafficSelector> getTreatmentAndMeta(
465 DeviceId deviceId, MacAddress hostMac, VlanId hostVlanId, PortNumber outPort,
466 VlanId innerVlan, EthType outerTpid)
467 throws DeviceConfigNotFoundException {
468 MacAddress routerMac;
469 routerMac = config.getDeviceMac(deviceId);
Charles Chan319d1a22015-11-03 10:42:14 -0800470
Charles Chan90772a72017-02-08 15:52:08 -0800471 ConnectPoint connectPoint = new ConnectPoint(deviceId, outPort);
Charles Chan098ca202018-05-01 11:50:20 -0700472 VlanId untaggedVlan = srManager.interfaceService.getUntaggedVlanId(connectPoint);
473 Set<VlanId> taggedVlans = srManager.interfaceService.getTaggedVlanId(connectPoint);
474 VlanId nativeVlan = srManager.interfaceService.getNativeVlanId(connectPoint);
sangho80f11cb2015-04-01 13:05:26 -0700475
Charles Chan90772a72017-02-08 15:52:08 -0800476 // Create route treatment
pierventre50e1bb82020-12-14 19:31:03 +0100477 TrafficTreatment.Builder tbuilder = DefaultTrafficTreatment.builder()
478 .deferred()
sangho27462c62015-05-14 00:39:53 -0700479 .setEthDst(hostMac)
Charles Chan61c086d2019-07-26 17:46:15 -0700480 .setEthSrc(routerMac)
sangho80f11cb2015-04-01 13:05:26 -0700481 .setOutput(outPort);
Saurav Das2d94d312015-11-24 23:21:05 -0800482
Charles Chan90772a72017-02-08 15:52:08 -0800483 // Create route meta
484 TrafficSelector.Builder mbuilder = DefaultTrafficSelector.builder();
Charles Chan10b0fb72017-02-02 16:20:42 -0800485
Charles Chan61c086d2019-07-26 17:46:15 -0700486 // Adjust treatment and meta according to VLAN configuration
Charles Chan90772a72017-02-08 15:52:08 -0800487 if (taggedVlans.contains(hostVlanId)) {
pierventre50e1bb82020-12-14 19:31:03 +0100488 mbuilder.matchVlanId(hostVlanId);
Charles Chan90772a72017-02-08 15:52:08 -0800489 tbuilder.setVlanId(hostVlanId);
490 } else if (hostVlanId.equals(VlanId.NONE)) {
491 if (untaggedVlan != null) {
492 mbuilder.matchVlanId(untaggedVlan);
pierventre50e1bb82020-12-14 19:31:03 +0100493 tbuilder.popVlan();
Charles Chan90772a72017-02-08 15:52:08 -0800494 } else if (nativeVlan != null) {
495 mbuilder.matchVlanId(nativeVlan);
pierventre50e1bb82020-12-14 19:31:03 +0100496 tbuilder.popVlan();
Charles Chan90772a72017-02-08 15:52:08 -0800497 } else {
Charles Chan3ed34d82017-06-22 18:03:14 -0700498 log.warn("Untagged nexthop {}/{} is not allowed on {} without untagged or native vlan",
499 hostMac, hostVlanId, connectPoint);
500 return null;
Charles Chan90772a72017-02-08 15:52:08 -0800501 }
502 } else {
Charles Chan61c086d2019-07-26 17:46:15 -0700503 // Double tagged hosts
504 if (innerVlan == null || outerTpid == null) {
505 log.warn("Failed to construct NextObj for double tagged hosts {}/{}. {} {}",
506 hostMac, hostVlanId,
507 (innerVlan == null) ? "innerVlan = null." : "",
508 (outerTpid == null) ? "outerTpid = null." : "");
Jonghwan Hyun9aaa34f2018-04-09 09:40:50 -0700509 return null;
510 }
Charles Chan61c086d2019-07-26 17:46:15 -0700511 tbuilder.setVlanId(innerVlan);
512 tbuilder.pushVlan(outerTpid);
513 tbuilder.setVlanId(hostVlanId);
514 mbuilder.matchVlanId(VlanId.ANY);
Saurav Das07c74602016-04-27 18:35:50 -0700515 }
Ruchi Sahota71bcb4e2019-01-28 01:08:18 +0000516
Charles Chan61c086d2019-07-26 17:46:15 -0700517 return ImmutablePair.of(tbuilder.build(), mbuilder.build());
sangho80f11cb2015-04-01 13:05:26 -0700518 }
519
520 /**
Saurav Das261c3002017-06-13 15:35:54 -0700521 * Populates IP flow rules for all the given prefixes reachable from the
522 * destination switch(es).
sangho80f11cb2015-04-01 13:05:26 -0700523 *
Saurav Das261c3002017-06-13 15:35:54 -0700524 * @param targetSw switch where rules are to be programmed
525 * @param subnets subnets/prefixes being added
526 * @param destSw1 destination switch where the prefixes are reachable
527 * @param destSw2 paired destination switch if one exists for the subnets/prefixes.
528 * Should be null if there is no paired destination switch (by config)
529 * or if the given prefixes are reachable only via destSw1
530 * @param nextHops a map containing a set of next-hops for each destination switch.
531 * If destSw2 is not null, then this map must contain an
532 * entry for destSw2 with its next-hops from the targetSw
533 * (although the next-hop set may be empty in certain scenarios).
534 * If destSw2 is null, there should not be an entry in this
535 * map for destSw2.
sangho80f11cb2015-04-01 13:05:26 -0700536 * @return true if all rules are set successfully, false otherwise
537 */
Charles Chan3ed34d82017-06-22 18:03:14 -0700538 boolean populateIpRuleForSubnet(DeviceId targetSw, Set<IpPrefix> subnets,
Saurav Das261c3002017-06-13 15:35:54 -0700539 DeviceId destSw1, DeviceId destSw2, Map<DeviceId, Set<DeviceId>> nextHops) {
psneha86e60d32019-03-26 06:31:41 -0400540 // Get pair device of the target switch
541 Optional<DeviceId> pairDev = srManager.getPairDeviceId(targetSw);
542 // Route simplification will be off in case of the nexthop location at target switch is down
543 // (routing through spine case)
544 boolean routeSimplOff = pairDev.isPresent() && pairDev.get().equals(destSw1) && destSw2 == null;
piera9941192019-04-24 16:12:47 +0200545 // Iterates over the routes. Checking:
psneha86e60d32019-03-26 06:31:41 -0400546 // If route simplification is enabled
547 // If the target device is another leaf in the network
548 if (srManager.routeSimplification && !routeSimplOff) {
piera9941192019-04-24 16:12:47 +0200549 Set<IpPrefix> subnetsToBePopulated = Sets.newHashSet();
psneha86e60d32019-03-26 06:31:41 -0400550 for (IpPrefix subnet : subnets) {
551 // Skip route programming on the target device
552 // If route simplification applies
553 if (routeSimplifierUtils.hasLeafExclusionEnabledForPrefix(subnet)) {
554 // XXX route simplification assumes that source of the traffic
555 // towards the nexthops are co-located with the nexthops. In different
556 // scenarios will not work properly.
557 continue;
558 }
559 // populate the route in the remaning scenarios
piera9941192019-04-24 16:12:47 +0200560 subnetsToBePopulated.add(subnet);
psneha86e60d32019-03-26 06:31:41 -0400561 }
piera9941192019-04-24 16:12:47 +0200562 subnets = subnetsToBePopulated;
sangho80f11cb2015-04-01 13:05:26 -0700563 }
piera9941192019-04-24 16:12:47 +0200564 // populate the remaining routes in the target switch
565 return populateIpRulesForRouter(targetSw, subnets, destSw1, destSw2, nextHops);
Charles Chanc22cef32016-04-29 14:38:22 -0700566 }
sangho80f11cb2015-04-01 13:05:26 -0700567
Charles Chanc22cef32016-04-29 14:38:22 -0700568 /**
Charles Chand66d6712018-03-29 16:03:41 -0700569 * Revokes IP flow rules for the subnets from given device.
Charles Chanc22cef32016-04-29 14:38:22 -0700570 *
Charles Chand66d6712018-03-29 16:03:41 -0700571 * @param targetSw target switch from which the subnets need to be removed
Charles Chanc22cef32016-04-29 14:38:22 -0700572 * @param subnets subnet being removed
573 * @return true if all rules are removed successfully, false otherwise
574 */
Charles Chand66d6712018-03-29 16:03:41 -0700575 boolean revokeIpRuleForSubnet(DeviceId targetSw, Set<IpPrefix> subnets) {
Charles Chanc22cef32016-04-29 14:38:22 -0700576 for (IpPrefix subnet : subnets) {
Charles Chand66d6712018-03-29 16:03:41 -0700577 if (!revokeIpRuleForRouter(targetSw, subnet)) {
Charles Chanc22cef32016-04-29 14:38:22 -0700578 return false;
579 }
580 }
sangho80f11cb2015-04-01 13:05:26 -0700581 return true;
582 }
583
584 /**
piera9941192019-04-24 16:12:47 +0200585 * Populates IP flow rules for a set of IP prefix in the target device.
586 * The prefix are reachable via destination device(s).
sangho80f11cb2015-04-01 13:05:26 -0700587 *
Saurav Das261c3002017-06-13 15:35:54 -0700588 * @param targetSw target device ID to set the rules
piera9941192019-04-24 16:12:47 +0200589 * @param subnets the set of IP prefix
Saurav Das261c3002017-06-13 15:35:54 -0700590 * @param destSw1 destination switch where the prefixes are reachable
591 * @param destSw2 paired destination switch if one exists for the subnets/prefixes.
592 * Should be null if there is no paired destination switch (by config)
593 * or if the given prefixes are reachable only via destSw1
594 * @param nextHops map of destination switches and their next-hops.
595 * Should only contain destination switches that are
596 * actually meant to be routed to. If destSw2 is null, there
597 * should not be an entry for destSw2 in this map.
sangho80f11cb2015-04-01 13:05:26 -0700598 * @return true if all rules are set successfully, false otherwise
599 */
piera9941192019-04-24 16:12:47 +0200600 private boolean populateIpRulesForRouter(DeviceId targetSw,
601 Set<IpPrefix> subnets,
602 DeviceId destSw1, DeviceId destSw2,
603 Map<DeviceId, Set<DeviceId>> nextHops) {
604 // pre-compute the needed information
605 int segmentIdIPv41, segmentIdIPv42 = -1;
606 int segmentIdIPv61, segmentIdIPv62 = -1;
607 TrafficTreatment treatment = null;
608 DestinationSet dsIPv4, dsIPv6;
609 TrafficSelector metaIpv4Selector, metaIpv6Selector = null;
610 int nextIdIPv4, nextIdIPv6, nextId;
611 TrafficSelector selector;
612 // start with MPLS SIDs
Charles Chan319d1a22015-11-03 10:42:14 -0800613 try {
piera9941192019-04-24 16:12:47 +0200614 segmentIdIPv41 = config.getIPv4SegmentId(destSw1);
615 segmentIdIPv61 = config.getIPv6SegmentId(destSw1);
616 if (destSw2 != null) {
617 segmentIdIPv42 = config.getIPv4SegmentId(destSw2);
618 segmentIdIPv62 = config.getIPv6SegmentId(destSw2);
Pier Ventreadb4ae62016-11-23 09:57:42 -0800619 }
Charles Chan319d1a22015-11-03 10:42:14 -0800620 } catch (DeviceConfigNotFoundException e) {
621 log.warn(e.getMessage() + " Aborting populateIpRuleForRouter.");
622 return false;
623 }
piera9941192019-04-24 16:12:47 +0200624 // build the IPv4 and IPv6 destination set
Saurav Das261c3002017-06-13 15:35:54 -0700625 if (destSw2 == null) {
626 // single dst - create destination set based on next-hop
Saurav Das97241862018-02-14 14:14:54 -0800627 // If the next hop is the same as the final destination, then MPLS
628 // label is not set.
Saurav Das261c3002017-06-13 15:35:54 -0700629 Set<DeviceId> nhd1 = nextHops.get(destSw1);
630 if (nhd1.size() == 1 && nhd1.iterator().next().equals(destSw1)) {
piera9941192019-04-24 16:12:47 +0200631 dsIPv4 = DestinationSet.createTypePushNone(destSw1);
632 dsIPv6 = DestinationSet.createTypePushNone(destSw1);
633 treatment = DefaultTrafficTreatment.builder()
634 .immediate()
635 .decNwTtl()
636 .build();
Saurav Das261c3002017-06-13 15:35:54 -0700637 } else {
piera9941192019-04-24 16:12:47 +0200638 dsIPv4 = DestinationSet.createTypePushBos(segmentIdIPv41, destSw1);
639 dsIPv6 = DestinationSet.createTypePushBos(segmentIdIPv61, destSw1);
Saurav Das261c3002017-06-13 15:35:54 -0700640 }
641 } else {
642 // dst pair - IP rules for dst-pairs are always from other edge nodes
643 // the destination set needs to have both destinations, even if there
644 // are no next hops to one of them
piera9941192019-04-24 16:12:47 +0200645 dsIPv4 = DestinationSet.createTypePushBos(segmentIdIPv41, destSw1, segmentIdIPv42, destSw2);
646 dsIPv6 = DestinationSet.createTypePushBos(segmentIdIPv61, destSw1, segmentIdIPv62, destSw2);
sangho80f11cb2015-04-01 13:05:26 -0700647 }
648
Saurav Das4c35fc42015-11-20 15:27:53 -0800649 // setup metadata to pass to nextObjective - indicate the vlan on egress
650 // if needed by the switch pipeline. Since neighbor sets are always to
651 // other neighboring routers, there is no subnet assigned on those ports.
piera9941192019-04-24 16:12:47 +0200652 metaIpv4Selector = buildIpv4Selector()
653 .matchVlanId(srManager.getDefaultInternalVlan())
654 .build();
655 metaIpv6Selector = buildIpv6Selector()
656 .matchVlanId(srManager.getDefaultInternalVlan())
657 .build();
658 // get the group handler of the target switch
Saurav Das261c3002017-06-13 15:35:54 -0700659 DefaultGroupHandler grpHandler = srManager.getGroupHandler(targetSw);
Saurav Das62ae6792017-05-15 15:34:25 -0700660 if (grpHandler == null) {
661 log.warn("populateIPRuleForRouter: groupHandler for device {} "
piera9941192019-04-24 16:12:47 +0200662 + "not found", targetSw);
Saurav Das62ae6792017-05-15 15:34:25 -0700663 return false;
664 }
piera9941192019-04-24 16:12:47 +0200665 // get next id
666 nextIdIPv4 = grpHandler.getNextObjectiveId(dsIPv4, nextHops, metaIpv4Selector, false);
667 if (nextIdIPv4 <= 0) {
668 log.warn("No next objective in {} for ds: {}", targetSw, dsIPv4);
sangho2165d222015-05-01 09:38:25 -0700669 return false;
670 }
piera9941192019-04-24 16:12:47 +0200671 nextIdIPv6 = grpHandler.getNextObjectiveId(dsIPv6, nextHops, metaIpv6Selector, false);
672 if (nextIdIPv6 <= 0) {
673 log.warn("No next objective in {} for ds: {}", targetSw, dsIPv6);
674 return false;
Charles Chanf4586112015-11-09 16:37:23 -0800675 }
piera9941192019-04-24 16:12:47 +0200676 // build all the flow rules and send to the device
677 for (IpPrefix subnet : subnets) {
678 selector = buildIpSelectorFromIpPrefix(subnet).build();
679 if (subnet.isIp4()) {
680 nextId = nextIdIPv4;
681 } else {
682 nextId = nextIdIPv6;
683 }
684 ForwardingObjective.Builder fwdBuilder = DefaultForwardingObjective
685 .builder()
686 .fromApp(srManager.appId)
687 .makePermanent()
688 .nextStep(nextId)
689 .withSelector(selector)
690 .withPriority(getPriorityFromPrefix(subnet))
691 .withFlag(ForwardingObjective.Flag.SPECIFIC);
692 if (treatment != null) {
693 fwdBuilder.withTreatment(treatment);
694 }
695 log.debug("Installing {} forwarding objective for router IP/subnet {} "
696 + "in switch {} with nextId: {}", subnet.isIp4() ? "IPv4" : "IPv6",
697 subnet, targetSw, nextId);
698 ObjectiveContext context = new DefaultObjectiveContext(
699 (objective) -> log.debug("IP rule for router {} populated in dev:{}",
700 subnet, targetSw),
701 (objective, error) -> log.warn("Failed to populate IP rule for router {}: {} in dev:{}",
702 subnet, error, targetSw));
703 srManager.flowObjectiveService.forward(targetSw, fwdBuilder.add(context));
704 }
705 rulePopulationCounter.addAndGet(subnets.size());
sangho80f11cb2015-04-01 13:05:26 -0700706 return true;
707 }
708
sangho80f11cb2015-04-01 13:05:26 -0700709 /**
Charles Chand66d6712018-03-29 16:03:41 -0700710 * Revokes IP flow rules for the router IP address from given device.
Charles Chanc22cef32016-04-29 14:38:22 -0700711 *
Charles Chand66d6712018-03-29 16:03:41 -0700712 * @param targetSw target switch from which the ipPrefix need to be removed
Charles Chanc22cef32016-04-29 14:38:22 -0700713 * @param ipPrefix the IP address of the destination router
714 * @return true if all rules are removed successfully, false otherwise
715 */
Charles Chand66d6712018-03-29 16:03:41 -0700716 private boolean revokeIpRuleForRouter(DeviceId targetSw, IpPrefix ipPrefix) {
Pier Ventre6b2c1b32016-12-09 17:26:04 -0800717 TrafficSelector.Builder sbuilder = buildIpSelectorFromIpPrefix(ipPrefix);
Charles Chanc22cef32016-04-29 14:38:22 -0700718 TrafficSelector selector = sbuilder.build();
719 TrafficTreatment dummyTreatment = DefaultTrafficTreatment.builder().build();
720
721 ForwardingObjective.Builder fwdBuilder = DefaultForwardingObjective
722 .builder()
723 .fromApp(srManager.appId)
724 .makePermanent()
725 .withSelector(selector)
726 .withTreatment(dummyTreatment)
727 .withPriority(getPriorityFromPrefix(ipPrefix))
728 .withFlag(ForwardingObjective.Flag.SPECIFIC);
729
Charles Chand66d6712018-03-29 16:03:41 -0700730 ObjectiveContext context = new DefaultObjectiveContext(
731 (objective) -> log.debug("IP rule for router {} revoked from {}", ipPrefix, targetSw),
732 (objective, error) -> log.warn("Failed to revoke IP rule for router {} from {}: {}",
733 ipPrefix, targetSw, error));
734 srManager.flowObjectiveService.forward(targetSw, fwdBuilder.remove(context));
Charles Chanc22cef32016-04-29 14:38:22 -0700735
736 return true;
737 }
738
739 /**
Saurav Das97241862018-02-14 14:14:54 -0800740 * Populates MPLS flow rules in the target device to point towards the
741 * destination device.
742 *
743 * @param targetSwId target device ID of the switch to set the rules
744 * @param destSwId destination switch device ID
745 * @param nextHops next hops switch ID list
746 * @param routerIp the router ip of the destination switch
747 * @return true if all rules are set successfully, false otherwise
748 */
749 boolean populateMplsRule(DeviceId targetSwId, DeviceId destSwId,
750 Set<DeviceId> nextHops, IpAddress routerIp) {
751 int segmentId;
752 try {
753 if (routerIp.isIp4()) {
754 segmentId = config.getIPv4SegmentId(destSwId);
755 } else {
756 segmentId = config.getIPv6SegmentId(destSwId);
757 }
758 } catch (DeviceConfigNotFoundException e) {
759 log.warn(e.getMessage() + " Aborting populateMplsRule.");
760 return false;
761 }
762
763 List<ForwardingObjective> fwdObjs = new ArrayList<>();
764 Collection<ForwardingObjective> fwdObjsMpls;
765 // Generates the transit rules used by the standard "routing".
766 fwdObjsMpls = handleMpls(targetSwId, destSwId, nextHops, segmentId,
767 routerIp, true);
768 if (fwdObjsMpls.isEmpty()) {
769 return false;
770 }
771 fwdObjs.addAll(fwdObjsMpls);
772
773 // Generates the transit rules used by the MPLS Pwaas.
774 int pwSrLabel;
775 try {
776 pwSrLabel = config.getPWRoutingLabel(destSwId);
777 } catch (DeviceConfigNotFoundException e) {
778 log.warn(e.getMessage()
779 + " Aborting populateMplsRule. No label for PseudoWire traffic.");
780 return false;
781 }
782 fwdObjsMpls = handleMpls(targetSwId, destSwId, nextHops, pwSrLabel,
783 routerIp, false);
784 if (fwdObjsMpls.isEmpty()) {
785 return false;
786 }
787 fwdObjs.addAll(fwdObjsMpls);
788
789 for (ForwardingObjective fwdObj : fwdObjs) {
790 log.debug("Sending MPLS fwd obj {} for SID {}-> next {} in sw: {}",
791 fwdObj.id(), segmentId, fwdObj.nextId(), targetSwId);
792 srManager.flowObjectiveService.forward(targetSwId, fwdObj);
793 rulePopulationCounter.incrementAndGet();
794 }
795
796 return true;
797 }
798
799 /**
800 * Differentiates between popping and swapping labels when building an MPLS
801 * forwarding objective.
Pier Ventre229fd0b2016-10-31 16:49:19 -0700802 *
803 * @param targetSwId the target sw
804 * @param destSwId the destination sw
805 * @param nextHops the set of next hops
Saurav Das97241862018-02-14 14:14:54 -0800806 * @param segmentId the segmentId to match representing the destination
807 * switch
808 * @param routerIp the router ip representing the destination switch
Pier Ventre229fd0b2016-10-31 16:49:19 -0700809 * @return a collection of fwdobjective
810 */
Saurav Das261c3002017-06-13 15:35:54 -0700811 private Collection<ForwardingObjective> handleMpls(
812 DeviceId targetSwId,
813 DeviceId destSwId,
814 Set<DeviceId> nextHops,
815 int segmentId,
816 IpAddress routerIp,
817 boolean isMplsBos) {
Pier Ventre229fd0b2016-10-31 16:49:19 -0700818
819 TrafficSelector.Builder sbuilder = DefaultTrafficSelector.builder();
820 List<ForwardingObjective.Builder> fwdObjBuilders = Lists.newArrayList();
Pier Luigi0be3f0f2017-01-30 09:47:36 -0800821 // For the transport of Pwaas we can use two or three MPLS label
Pier Ventre229fd0b2016-10-31 16:49:19 -0700822 sbuilder.matchEthType(Ethernet.MPLS_UNICAST);
823 sbuilder.matchMplsLabel(MplsLabel.mplsLabel(segmentId));
824 sbuilder.matchMplsBos(isMplsBos);
825 TrafficSelector selector = sbuilder.build();
826
827 // setup metadata to pass to nextObjective - indicate the vlan on egress
828 // if needed by the switch pipeline. Since mpls next-hops are always to
829 // other neighboring routers, there is no subnet assigned on those ports.
830 TrafficSelector.Builder metabuilder = DefaultTrafficSelector.builder(selector);
Saurav Das9bf49582018-08-13 15:34:26 -0700831 metabuilder.matchVlanId(srManager.getDefaultInternalVlan());
Pier Ventre229fd0b2016-10-31 16:49:19 -0700832
833 if (nextHops.size() == 1 && destSwId.equals(nextHops.toArray()[0])) {
834 // If the next hop is the destination router for the segment, do pop
835 log.debug("populateMplsRule: Installing MPLS forwarding objective for "
Saurav Das261c3002017-06-13 15:35:54 -0700836 + "label {} in switch {} with pop to next-hops {}",
837 segmentId, targetSwId, nextHops);
Saurav Das2cb38292017-03-29 19:09:17 -0700838 ForwardingObjective.Builder fwdObjNoBosBuilder =
839 getMplsForwardingObjective(targetSwId,
840 nextHops,
841 true,
842 isMplsBos,
843 metabuilder.build(),
Saurav Das62ae6792017-05-15 15:34:25 -0700844 routerIp,
Saurav Das97241862018-02-14 14:14:54 -0800845 segmentId,
Saurav Das62ae6792017-05-15 15:34:25 -0700846 destSwId);
Pier Ventre229fd0b2016-10-31 16:49:19 -0700847 // Error case, we cannot handle, exit.
848 if (fwdObjNoBosBuilder == null) {
849 return Collections.emptyList();
850 }
851 fwdObjBuilders.add(fwdObjNoBosBuilder);
852
853 } else {
Saurav Das97241862018-02-14 14:14:54 -0800854 // next hop is not destination, irrespective of the number of next
855 // hops (1 or more) -- SR CONTINUE case (swap with self)
Saurav Das261c3002017-06-13 15:35:54 -0700856 log.debug("Installing MPLS forwarding objective for "
857 + "label {} in switch {} without pop to next-hops {}",
858 segmentId, targetSwId, nextHops);
Saurav Das2cb38292017-03-29 19:09:17 -0700859 ForwardingObjective.Builder fwdObjNoBosBuilder =
860 getMplsForwardingObjective(targetSwId,
861 nextHops,
862 false,
863 isMplsBos,
864 metabuilder.build(),
Saurav Das62ae6792017-05-15 15:34:25 -0700865 routerIp,
Saurav Das97241862018-02-14 14:14:54 -0800866 segmentId,
Saurav Das62ae6792017-05-15 15:34:25 -0700867 destSwId);
Pier Ventre229fd0b2016-10-31 16:49:19 -0700868 // Error case, we cannot handle, exit.
869 if (fwdObjNoBosBuilder == null) {
870 return Collections.emptyList();
871 }
872 fwdObjBuilders.add(fwdObjNoBosBuilder);
873
874 }
875
876 List<ForwardingObjective> fwdObjs = Lists.newArrayList();
877 // We add the final property to the fwdObjs.
878 for (ForwardingObjective.Builder fwdObjBuilder : fwdObjBuilders) {
Pier Ventre229fd0b2016-10-31 16:49:19 -0700879 ((Builder) ((Builder) fwdObjBuilder
880 .fromApp(srManager.appId)
881 .makePermanent())
882 .withSelector(selector)
883 .withPriority(SegmentRoutingService.DEFAULT_PRIORITY))
884 .withFlag(ForwardingObjective.Flag.SPECIFIC);
885
886 ObjectiveContext context = new DefaultObjectiveContext(
887 (objective) ->
888 log.debug("MPLS rule {} for SID {} populated in dev:{} ",
889 objective.id(), segmentId, targetSwId),
890 (objective, error) ->
891 log.warn("Failed to populate MPLS rule {} for SID {}: {} in dev:{}",
892 objective.id(), segmentId, error, targetSwId));
893
894 ForwardingObjective fob = fwdObjBuilder.add(context);
895 fwdObjs.add(fob);
Pier Ventre229fd0b2016-10-31 16:49:19 -0700896 }
897
898 return fwdObjs;
899 }
900
901 /**
Saurav Das97241862018-02-14 14:14:54 -0800902 * Returns a Forwarding Objective builder for the MPLS rule that references
903 * the desired Next Objective. Creates a DestinationSet that allows the
904 * groupHandler to create or find the required next objective.
sangho80f11cb2015-04-01 13:05:26 -0700905 *
Saurav Das97241862018-02-14 14:14:54 -0800906 * @param targetSw the target sw
907 * @param nextHops the set of next hops
908 * @param phpRequired true if penultimate-hop-popping is required
909 * @param isBos true if matched label is bottom-of-stack
910 * @param meta metadata for creating next objective
911 * @param routerIp the router ip representing the destination switch
912 * @param destSw the destination sw
913 * @return the mpls forwarding objective builder
sangho80f11cb2015-04-01 13:05:26 -0700914 */
Saurav Das4c35fc42015-11-20 15:27:53 -0800915 private ForwardingObjective.Builder getMplsForwardingObjective(
Saurav Das261c3002017-06-13 15:35:54 -0700916 DeviceId targetSw,
Saurav Das4c35fc42015-11-20 15:27:53 -0800917 Set<DeviceId> nextHops,
918 boolean phpRequired,
919 boolean isBos,
Pier Ventreadb4ae62016-11-23 09:57:42 -0800920 TrafficSelector meta,
Saurav Das62ae6792017-05-15 15:34:25 -0700921 IpAddress routerIp,
Saurav Das97241862018-02-14 14:14:54 -0800922 int segmentId,
Saurav Das62ae6792017-05-15 15:34:25 -0700923 DeviceId destSw) {
Saurav Das4c35fc42015-11-20 15:27:53 -0800924
Srikanth Vavilapalli64505482015-04-21 13:04:13 -0700925 ForwardingObjective.Builder fwdBuilder = DefaultForwardingObjective
926 .builder().withFlag(ForwardingObjective.Flag.SPECIFIC);
sangho80f11cb2015-04-01 13:05:26 -0700927
928 TrafficTreatment.Builder tbuilder = DefaultTrafficTreatment.builder();
Saurav Das97241862018-02-14 14:14:54 -0800929 DestinationSet ds = null;
Andreas Pantelopoulosb281ae22018-05-01 14:56:05 -0700930 DestinationSet.DestinationSetType dstType = null;
Saurav Das97241862018-02-14 14:14:54 -0800931 boolean simple = false;
sangho80f11cb2015-04-01 13:05:26 -0700932 if (phpRequired) {
Saurav Das4c35fc42015-11-20 15:27:53 -0800933 // php case - pop should always be flow-action
Srikanth Vavilapalli64505482015-04-21 13:04:13 -0700934 log.debug("getMplsForwardingObjective: php required");
sangho27462c62015-05-14 00:39:53 -0700935 tbuilder.deferred().copyTtlIn();
sangho80f11cb2015-04-01 13:05:26 -0700936 if (isBos) {
Pier Ventreadb4ae62016-11-23 09:57:42 -0800937 if (routerIp.isIp4()) {
938 tbuilder.deferred().popMpls(EthType.EtherType.IPV4.ethType());
939 } else {
940 tbuilder.deferred().popMpls(EthType.EtherType.IPV6.ethType());
941 }
942 tbuilder.decNwTtl();
Saurav Das97241862018-02-14 14:14:54 -0800943 // standard case -> BoS == True; pop results in IP packet and forwarding
944 // is via an ECMP group
Andreas Pantelopoulosb281ae22018-05-01 14:56:05 -0700945 ds = DestinationSet.createTypePopBos(destSw);
sangho80f11cb2015-04-01 13:05:26 -0700946 } else {
Saurav Das4c35fc42015-11-20 15:27:53 -0800947 tbuilder.deferred().popMpls(EthType.EtherType.MPLS_UNICAST.ethType())
948 .decMplsTtl();
Saurav Das97241862018-02-14 14:14:54 -0800949 // double-label case -> BoS == False, pop results in MPLS packet
950 // depending on configuration we can ECMP this packet or choose one output
Andreas Pantelopoulosb281ae22018-05-01 14:56:05 -0700951 ds = DestinationSet.createTypePopNotBos(destSw);
952 if (!srManager.getMplsEcmp()) {
953 simple = true;
Saurav Das97241862018-02-14 14:14:54 -0800954 }
sangho80f11cb2015-04-01 13:05:26 -0700955 }
956 } else {
Saurav Das4c35fc42015-11-20 15:27:53 -0800957 // swap with self case - SR CONTINUE
Saurav Das97241862018-02-14 14:14:54 -0800958 log.debug("getMplsForwardingObjective: swap with self");
sangho27462c62015-05-14 00:39:53 -0700959 tbuilder.deferred().decMplsTtl();
Saurav Das97241862018-02-14 14:14:54 -0800960 // swap results in MPLS packet with same BoS bit regardless of bit value
961 // depending on configuration we can ECMP this packet or choose one output
Andreas Pantelopoulosb281ae22018-05-01 14:56:05 -0700962 // differentiate here between swap with not bos or swap with bos
963 ds = isBos ? DestinationSet.createTypeSwapBos(segmentId, destSw) :
964 DestinationSet.createTypeSwapNotBos(segmentId, destSw);
965 if (!srManager.getMplsEcmp()) {
Saurav Das97241862018-02-14 14:14:54 -0800966 simple = true;
967 }
sangho80f11cb2015-04-01 13:05:26 -0700968 }
969
Saurav Das4c35fc42015-11-20 15:27:53 -0800970 fwdBuilder.withTreatment(tbuilder.build());
Saurav Das97241862018-02-14 14:14:54 -0800971 log.debug("Trying to get a nextObjId for mpls rule on device:{} to ds:{}",
972 targetSw, ds);
Saurav Das261c3002017-06-13 15:35:54 -0700973 DefaultGroupHandler gh = srManager.getGroupHandler(targetSw);
974 if (gh == null) {
975 log.warn("getNextObjectiveId query - groupHandler for device {} "
976 + "not found", targetSw);
977 return null;
978 }
Saurav Das97241862018-02-14 14:14:54 -0800979
Saurav Das261c3002017-06-13 15:35:54 -0700980 Map<DeviceId, Set<DeviceId>> dstNextHops = new HashMap<>();
981 dstNextHops.put(destSw, nextHops);
Saurav Das97241862018-02-14 14:14:54 -0800982 int nextId = gh.getNextObjectiveId(ds, dstNextHops, meta, simple);
Saurav Das4c35fc42015-11-20 15:27:53 -0800983 if (nextId <= 0) {
Saurav Das97241862018-02-14 14:14:54 -0800984 log.warn("No next objective in {} for ds: {}", targetSw, ds);
Saurav Das4c35fc42015-11-20 15:27:53 -0800985 return null;
Saurav Dase0237a32016-05-27 13:54:07 -0700986 } else {
Saurav Das97241862018-02-14 14:14:54 -0800987 log.debug("nextObjId found:{} for mpls rule on device:{} to ds:{}",
988 nextId, targetSw, ds);
sangho80f11cb2015-04-01 13:05:26 -0700989 }
990
Saurav Das4c35fc42015-11-20 15:27:53 -0800991 fwdBuilder.nextStep(nextId);
Srikanth Vavilapalli64505482015-04-21 13:04:13 -0700992 return fwdBuilder;
sangho80f11cb2015-04-01 13:05:26 -0700993 }
994
995 /**
Saurav Das9f1c42e2015-10-23 10:51:11 -0700996 * Creates a filtering objective to permit all untagged packets with a
Saurav Das7c305372015-10-28 12:39:42 -0700997 * dstMac corresponding to the router's MAC address. For those pipelines
998 * that need to internally assign vlans to untagged packets, this method
999 * provides per-subnet vlan-ids as metadata.
Saurav Dasc28b3432015-10-30 17:45:38 -07001000 * <p>
Saurav Dasf9332192017-02-18 14:05:44 -08001001 * Note that the vlan assignment and filter programming should only be done by
1002 * the master for a switch. This method is typically called at deviceAdd and
1003 * programs filters only for the enabled ports of the device. For port-updates,
1004 * that enable/disable ports after device add, singlePortFilter methods should
1005 * be called.
sangho80f11cb2015-04-01 13:05:26 -07001006 *
Saurav Das9f1c42e2015-10-23 10:51:11 -07001007 * @param deviceId the switch dpid for the router
Saurav Dasd1872b02016-12-02 15:43:47 -08001008 * @return PortFilterInfo information about the processed ports
sangho80f11cb2015-04-01 13:05:26 -07001009 */
Charles Chan3ed34d82017-06-22 18:03:14 -07001010 PortFilterInfo populateVlanMacFilters(DeviceId deviceId) {
Saurav Das7c305372015-10-28 12:39:42 -07001011 log.debug("Installing per-port filtering objective for untagged "
1012 + "packets in device {}", deviceId);
Charles Chan319d1a22015-11-03 10:42:14 -08001013
Saurav Das07c74602016-04-27 18:35:50 -07001014 List<Port> devPorts = srManager.deviceService.getPorts(deviceId);
Jon Hall31d84782017-01-18 20:15:44 -08001015 if (devPorts == null || devPorts.isEmpty()) {
Saurav Das07c74602016-04-27 18:35:50 -07001016 log.warn("Device {} ports not available. Unable to add MacVlan filters",
1017 deviceId);
Saurav Dasd1872b02016-12-02 15:43:47 -08001018 return null;
Saurav Das07c74602016-04-27 18:35:50 -07001019 }
Saurav Dasf9332192017-02-18 14:05:44 -08001020 int disabledPorts = 0, errorPorts = 0, filteredPorts = 0;
Saurav Das07c74602016-04-27 18:35:50 -07001021 for (Port port : devPorts) {
Saurav Dase0237a32016-05-27 13:54:07 -07001022 if (!port.isEnabled()) {
1023 disabledPorts++;
1024 continue;
1025 }
Charles Chan43be46b2017-02-26 22:59:35 -08001026 if (processSinglePortFilters(deviceId, port.number(), true)) {
Saurav Dasf9332192017-02-18 14:05:44 -08001027 filteredPorts++;
1028 } else {
1029 errorPorts++;
Saurav Dase0237a32016-05-27 13:54:07 -07001030 }
Saurav Das7c305372015-10-28 12:39:42 -07001031 }
Charles Chan077314e2017-06-22 14:27:17 -07001032 log.debug("Filtering on dev:{}, disabledPorts:{}, errorPorts:{}, filteredPorts:{}",
Saurav Dasf9332192017-02-18 14:05:44 -08001033 deviceId, disabledPorts, errorPorts, filteredPorts);
Charles Chan9d2dd552018-06-19 20:56:33 -07001034 return new PortFilterInfo(disabledPorts, errorPorts, filteredPorts);
Saurav Dasf9332192017-02-18 14:05:44 -08001035 }
1036
1037 /**
Charles Chan43be46b2017-02-26 22:59:35 -08001038 * Creates or removes filtering objectives for a single port. Should only be
1039 * called by the master for a switch.
Saurav Dasf9332192017-02-18 14:05:44 -08001040 *
1041 * @param deviceId device identifier
1042 * @param portnum port identifier for port to be filtered
Charles Chan43be46b2017-02-26 22:59:35 -08001043 * @param install true to install the filtering objective, false to remove
Saurav Dasf9332192017-02-18 14:05:44 -08001044 * @return true if no errors occurred during the build of the filtering objective
1045 */
Charles Chan3ed34d82017-06-22 18:03:14 -07001046 boolean processSinglePortFilters(DeviceId deviceId, PortNumber portnum, boolean install) {
Charles Chan90772a72017-02-08 15:52:08 -08001047 ConnectPoint connectPoint = new ConnectPoint(deviceId, portnum);
Charles Chan098ca202018-05-01 11:50:20 -07001048 VlanId untaggedVlan = srManager.interfaceService.getUntaggedVlanId(connectPoint);
1049 Set<VlanId> taggedVlans = srManager.interfaceService.getTaggedVlanId(connectPoint);
1050 VlanId nativeVlan = srManager.interfaceService.getNativeVlanId(connectPoint);
Charles Chan90772a72017-02-08 15:52:08 -08001051
Jonghwan Hyun9aaa34f2018-04-09 09:40:50 -07001052 // Do not configure filter for edge ports where double-tagged hosts are connected.
Charles Chan90772a72017-02-08 15:52:08 -08001053 if (taggedVlans.size() != 0) {
1054 // Filter for tagged vlans
Charles Chan098ca202018-05-01 11:50:20 -07001055 if (!srManager.interfaceService.getTaggedVlanId(connectPoint).stream().allMatch(taggedVlanId ->
Charles Chan43be46b2017-02-26 22:59:35 -08001056 processSinglePortFiltersInternal(deviceId, portnum, false, taggedVlanId, install))) {
Charles Chan90772a72017-02-08 15:52:08 -08001057 return false;
1058 }
1059 if (nativeVlan != null) {
1060 // Filter for native vlan
Charles Chan43be46b2017-02-26 22:59:35 -08001061 if (!processSinglePortFiltersInternal(deviceId, portnum, true, nativeVlan, install)) {
Charles Chan90772a72017-02-08 15:52:08 -08001062 return false;
1063 }
1064 }
1065 } else if (untaggedVlan != null) {
1066 // Filter for untagged vlan
Charles Chan43be46b2017-02-26 22:59:35 -08001067 if (!processSinglePortFiltersInternal(deviceId, portnum, true, untaggedVlan, install)) {
Charles Chan90772a72017-02-08 15:52:08 -08001068 return false;
1069 }
Jonghwan Hyun671a7ab2018-04-30 09:27:21 -07001070 } else if (!hasIPConfiguration(connectPoint)) {
Jonghwan Hyun9aaa34f2018-04-09 09:40:50 -07001071 // Filter for unconfigured upstream port, using INTERNAL_VLAN
Saurav Das9bf49582018-08-13 15:34:26 -07001072 if (!processSinglePortFiltersInternal(deviceId, portnum, true,
1073 srManager.getDefaultInternalVlan(),
1074 install)) {
Charles Chan90772a72017-02-08 15:52:08 -08001075 return false;
1076 }
Andreas Pantelopoulosb281ae22018-05-01 14:56:05 -07001077 // Filter for receiveing pseudowire traffic
Saurav Das9bf49582018-08-13 15:34:26 -07001078 if (!processSinglePortFiltersInternal(deviceId, portnum, false,
1079 srManager.getPwTransportVlan(),
1080 install)) {
Andreas Pantelopoulosb281ae22018-05-01 14:56:05 -07001081 return false;
1082 }
Charles Chan90772a72017-02-08 15:52:08 -08001083 }
1084 return true;
1085 }
1086
Jonghwan Hyune5ef7622017-08-25 17:48:36 -07001087 /**
1088 * Updates filtering objectives for a single port. Should only be called by
1089 * the master for a switch
1090 * @param deviceId device identifier
1091 * @param portNum port identifier for port to be filtered
1092 * @param pushVlan true to push vlan, false otherwise
1093 * @param vlanId vlan identifier
1094 * @param install true to install the filtering objective, false to remove
1095 */
1096 void updateSinglePortFilters(DeviceId deviceId, PortNumber portNum,
1097 boolean pushVlan, VlanId vlanId, boolean install) {
1098 if (!processSinglePortFiltersInternal(deviceId, portNum, pushVlan, vlanId, install)) {
1099 log.warn("Failed to update FilteringObjective for {}/{} with vlan {}",
1100 deviceId, portNum, vlanId);
1101 }
1102 }
1103
Charles Chan43be46b2017-02-26 22:59:35 -08001104 private boolean processSinglePortFiltersInternal(DeviceId deviceId, PortNumber portnum,
1105 boolean pushVlan, VlanId vlanId, boolean install) {
Daniel Ginsburg776789f2018-04-30 19:27:19 -04001106 boolean doTMAC = true;
1107
1108 if (!pushVlan) {
1109 // Skip the tagged vlans belonging to an interface without an IP address
1110 Set<Interface> ifaces = srManager.interfaceService
1111 .getInterfacesByPort(new ConnectPoint(deviceId, portnum))
1112 .stream()
1113 .filter(intf -> intf.vlanTagged().contains(vlanId) && intf.ipAddressesList().isEmpty())
1114 .collect(Collectors.toSet());
1115 if (!ifaces.isEmpty()) {
1116 log.debug("processSinglePortFiltersInternal: skipping TMAC for vlan {} at {}/{} - no IP",
1117 vlanId, deviceId, portnum);
1118 doTMAC = false;
1119 }
1120 }
1121
1122 FilteringObjective.Builder fob = buildFilteringObjective(deviceId, portnum, pushVlan, vlanId, doTMAC);
Saurav Dasf9332192017-02-18 14:05:44 -08001123 if (fob == null) {
1124 // error encountered during build
1125 return false;
1126 }
Jonghwan Hyune5ef7622017-08-25 17:48:36 -07001127 log.debug("{} filtering objectives for dev/port: {}/{}",
Saurav Das62ae6792017-05-15 15:34:25 -07001128 install ? "Installing" : "Removing", deviceId, portnum);
Saurav Dasf9332192017-02-18 14:05:44 -08001129 ObjectiveContext context = new DefaultObjectiveContext(
Charles Chan43be46b2017-02-26 22:59:35 -08001130 (objective) -> log.debug("Filter for {}/{} {}", deviceId, portnum,
Saurav Das62ae6792017-05-15 15:34:25 -07001131 install ? "installed" : "removed"),
Charles Chan43be46b2017-02-26 22:59:35 -08001132 (objective, error) -> log.warn("Failed to {} filter for {}/{}: {}",
Saurav Das62ae6792017-05-15 15:34:25 -07001133 install ? "install" : "remove", deviceId, portnum, error));
Charles Chan43be46b2017-02-26 22:59:35 -08001134 if (install) {
1135 srManager.flowObjectiveService.filter(deviceId, fob.add(context));
1136 } else {
1137 srManager.flowObjectiveService.filter(deviceId, fob.remove(context));
Charles Chan90772a72017-02-08 15:52:08 -08001138 }
Charles Chan90772a72017-02-08 15:52:08 -08001139 return true;
Saurav Dasf9332192017-02-18 14:05:44 -08001140 }
1141
Charles Chan90772a72017-02-08 15:52:08 -08001142 private FilteringObjective.Builder buildFilteringObjective(DeviceId deviceId, PortNumber portnum,
Daniel Ginsburg776789f2018-04-30 19:27:19 -04001143 boolean pushVlan, VlanId vlanId, boolean doTMAC) {
Saurav Dasf9332192017-02-18 14:05:44 -08001144 MacAddress deviceMac;
1145 try {
1146 deviceMac = config.getDeviceMac(deviceId);
1147 } catch (DeviceConfigNotFoundException e) {
1148 log.warn(e.getMessage() + " Processing SinglePortFilters aborted");
1149 return null;
1150 }
Saurav Dasf9332192017-02-18 14:05:44 -08001151 FilteringObjective.Builder fob = DefaultFilteringObjective.builder();
Daniel Ginsburg776789f2018-04-30 19:27:19 -04001152
1153 if (doTMAC) {
1154 fob.withKey(Criteria.matchInPort(portnum))
1155 .addCondition(Criteria.matchEthDst(deviceMac))
1156 .withPriority(SegmentRoutingService.DEFAULT_PRIORITY);
1157 } else {
1158 fob.withKey(Criteria.matchInPort(portnum))
1159 .withPriority(SegmentRoutingService.DEFAULT_PRIORITY);
1160 }
Charles Chan90772a72017-02-08 15:52:08 -08001161
Charles Chan17ca2202017-12-19 19:55:57 -08001162 TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder();
1163
Charles Chan90772a72017-02-08 15:52:08 -08001164 if (pushVlan) {
1165 fob.addCondition(Criteria.matchVlanId(VlanId.NONE));
Charles Chan17ca2202017-12-19 19:55:57 -08001166 tBuilder.pushVlan().setVlanId(vlanId);
Charles Chan90772a72017-02-08 15:52:08 -08001167 } else {
1168 fob.addCondition(Criteria.matchVlanId(vlanId));
1169 }
1170
Charles Chan17ca2202017-12-19 19:55:57 -08001171 // NOTE: Some switch hardware share the same filtering flow among different ports.
1172 // We use this metadata to let the driver know that there is no more enabled port
1173 // within the same VLAN on this device.
Charles Chanf17f66b2018-02-26 21:33:25 -08001174 if (noMoreEnabledPort(deviceId, vlanId)) {
Charles Chan17ca2202017-12-19 19:55:57 -08001175 tBuilder.wipeDeferred();
1176 }
1177
1178 fob.withMeta(tBuilder.build());
1179
Saurav Dasf9332192017-02-18 14:05:44 -08001180 fob.permit().fromApp(srManager.appId);
1181 return fob;
sangho80f11cb2015-04-01 13:05:26 -07001182 }
1183
1184 /**
Jonghwan Hyun9aaa34f2018-04-09 09:40:50 -07001185 * Creates or removes filtering objectives for a double-tagged host on a port.
1186 *
1187 * @param deviceId device identifier
1188 * @param portNum port identifier for port to be filtered
1189 * @param outerVlan outer VLAN ID
1190 * @param innerVlan inner VLAN ID
1191 * @param install true to install the filtering objective, false to remove
1192 */
1193 void processDoubleTaggedFilter(DeviceId deviceId, PortNumber portNum, VlanId outerVlan,
1194 VlanId innerVlan, boolean install) {
Daniele Moro8fc37b42019-10-29 18:48:35 -07001195 // We should trigger the removal of double tagged rules only when removing
1196 // the filtering objective and no other hosts are connected to the same device port.
Charles Chanf17fade2020-03-08 18:07:19 -07001197 boolean cleanupDoubleTaggedRules = !anyDoubleTaggedHost(deviceId, portNum) && !install;
Daniele Moro8fc37b42019-10-29 18:48:35 -07001198 FilteringObjective.Builder fob = buildDoubleTaggedFilteringObj(deviceId, portNum,
1199 outerVlan, innerVlan,
1200 cleanupDoubleTaggedRules);
Jonghwan Hyun9aaa34f2018-04-09 09:40:50 -07001201 if (fob == null) {
1202 // error encountered during build
1203 return;
1204 }
1205 log.debug("{} double-tagged filtering objectives for dev/port: {}/{}",
1206 install ? "Installing" : "Removing", deviceId, portNum);
1207 ObjectiveContext context = new DefaultObjectiveContext(
1208 (objective) -> log.debug("Filter for {}/{} {}", deviceId, portNum,
1209 install ? "installed" : "removed"),
1210 (objective, error) -> log.warn("Failed to {} filter for {}/{}: {}",
1211 install ? "install" : "remove", deviceId, portNum, error));
1212 if (install) {
1213 srManager.flowObjectiveService.filter(deviceId, fob.add(context));
1214 } else {
1215 srManager.flowObjectiveService.filter(deviceId, fob.remove(context));
1216 }
1217 }
1218
Charles Chanf17fade2020-03-08 18:07:19 -07001219 /**
1220 * Checks if there is any double tagged host attached to given location.
1221 * This method will match on the effective location of a host.
1222 * That is, it will match on auxLocations when auxLocations is not null. Otherwise, it will match on locations.
1223 *
1224 * @param deviceId device ID
1225 * @param portNum port number
1226 * @return true if there is any host attached to given location.
1227 */
1228 private boolean anyDoubleTaggedHost(DeviceId deviceId, PortNumber portNum) {
1229 ConnectPoint cp = new ConnectPoint(deviceId, portNum);
1230 Set<Host> connectedHosts = srManager.hostService.getConnectedHosts(cp, false);
1231 Set<Host> auxConnectedHosts = srManager.hostService.getConnectedHosts(cp, true);
1232 return !auxConnectedHosts.isEmpty() ||
1233 connectedHosts.stream().anyMatch(host -> host.auxLocations() == null);
1234 }
1235
Jonghwan Hyun9aaa34f2018-04-09 09:40:50 -07001236 private FilteringObjective.Builder buildDoubleTaggedFilteringObj(DeviceId deviceId, PortNumber portNum,
Andreas Pantelopoulos59bd97e2018-06-28 17:06:14 -07001237 VlanId outerVlan, VlanId innerVlan,
1238 boolean cleanupDoubleTaggedRules) {
Jonghwan Hyun9aaa34f2018-04-09 09:40:50 -07001239 MacAddress deviceMac;
1240 try {
1241 deviceMac = config.getDeviceMac(deviceId);
1242 } catch (DeviceConfigNotFoundException e) {
1243 log.warn(e.getMessage() + " Processing DoubleTaggedFilters aborted");
1244 return null;
1245 }
1246 FilteringObjective.Builder fob = DefaultFilteringObjective.builder();
1247 // Outer vlan id match should be appeared before inner vlan id match.
1248 fob.withKey(Criteria.matchInPort(portNum))
1249 .addCondition(Criteria.matchEthDst(deviceMac))
1250 .addCondition(Criteria.matchVlanId(outerVlan))
Daniele Moro998f2df2019-07-12 17:58:54 -07001251 .addCondition(Criteria.matchInnerVlanId(innerVlan))
Jonghwan Hyun9aaa34f2018-04-09 09:40:50 -07001252 .withPriority(SegmentRoutingService.DEFAULT_PRIORITY);
1253
1254 TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder();
1255 // Pop outer vlan
1256 tBuilder.popVlan();
1257
Andreas Pantelopoulos59bd97e2018-06-28 17:06:14 -07001258 // special metadata for driver
1259 if (cleanupDoubleTaggedRules) {
1260 tBuilder.writeMetadata(CLEANUP_DOUBLE_TAGGED_HOST_ENTRIES, DOUBLE_TAGGED_METADATA_MASK);
1261 } else {
1262 tBuilder.writeMetadata(0, DOUBLE_TAGGED_METADATA_MASK);
1263 }
1264
Jonghwan Hyun9aaa34f2018-04-09 09:40:50 -07001265 // NOTE: Some switch hardware share the same filtering flow among different ports.
1266 // We use this metadata to let the driver know that there is no more enabled port
1267 // within the same VLAN on this device.
1268 if (noMoreEnabledPort(deviceId, outerVlan)) {
1269 tBuilder.wipeDeferred();
1270 }
1271
1272 fob.withMeta(tBuilder.build());
1273
1274 fob.permit().fromApp(srManager.appId);
1275 return fob;
1276 }
1277
1278 /**
Danny Chang44a7b952020-09-08 15:27:04 -07001279 * Creates packet requests to punt all IP packets for the router.
1280 * @param deviceId the switch dpid for the router
1281 */
1282 void populateIpPunts(DeviceId deviceId) {
1283 manageIpPunts(deviceId, true);
1284 }
1285
1286 /**
1287 * Creates a packet request to punt all IP packets, destined to the
1288 * specified IP address, which should be router's port IP address.
1289 *
1290 * @param deviceId the switch dpid for the router
1291 * @param ipAddress the IP address of the router's port
1292 */
1293 void populateSingleIpPunts(DeviceId deviceId, IpAddress ipAddress) {
1294 manageSingleIpPunts(deviceId, ipAddress, true);
1295 }
1296
1297 /**
1298 * Revokes packet requests for all devices.
1299 */
1300 void revokePacketsPunts() {
1301 srManager.deviceService.getDevices().forEach(device -> {
1302 manageIpPunts(device.id(), false);
1303 });
1304 }
1305
1306 /**
1307 * Revokes the packet request to punt all IP packets, destined to the
1308 * router's port IP address, except for the router's IP address.
1309 *
1310 * @param deviceId the switch dpid for the router
1311 * @param ipAddress the IP address of the router's port
1312 */
1313 void revokeSingleIpPunts(DeviceId deviceId, IpAddress ipAddress) {
1314 try {
1315 if (!ipAddress.equals(config.getRouterIpv4(deviceId)) &&
1316 !ipAddress.equals(config.getRouterIpv6(deviceId))) {
1317 manageSingleIpPunts(deviceId, ipAddress, false);
1318 }
1319 } catch (DeviceConfigNotFoundException e) {
1320 log.warn(e.getMessage() + " Aborting revokeSingleIpPunts");
1321 }
1322 }
1323
1324 /**
1325 * Creates or removes forwarding objectives ( packet-requests ) to punt all IP packets, destined to the
Saurav Dasc28b3432015-10-30 17:45:38 -07001326 * router's port IP addresses, to the controller. Note that the input
Saurav Das9f1c42e2015-10-23 10:51:11 -07001327 * port should not be matched on, as these packets can come from any input.
Saurav Dasc28b3432015-10-30 17:45:38 -07001328 * Furthermore, these are applied only by the master instance.
sangho80f11cb2015-04-01 13:05:26 -07001329 *
Saurav Das9f1c42e2015-10-23 10:51:11 -07001330 * @param deviceId the switch dpid for the router
Danny Chang44a7b952020-09-08 15:27:04 -07001331 * @param request true to create a packet request, false to remove
sangho80f11cb2015-04-01 13:05:26 -07001332 */
Danny Chang44a7b952020-09-08 15:27:04 -07001333 void manageIpPunts(DeviceId deviceId, boolean request) {
Saurav Das261c3002017-06-13 15:35:54 -07001334 Ip4Address routerIpv4, pairRouterIpv4 = null;
Charles Chanef8d12e2017-12-05 21:07:38 -08001335 Ip6Address routerIpv6, routerLinkLocalIpv6, pairRouterIpv6 = null;
Charles Chan319d1a22015-11-03 10:42:14 -08001336 try {
Pier Ventreadb4ae62016-11-23 09:57:42 -08001337 routerIpv4 = config.getRouterIpv4(deviceId);
1338 routerIpv6 = config.getRouterIpv6(deviceId);
Charles Chanef8d12e2017-12-05 21:07:38 -08001339 routerLinkLocalIpv6 = Ip6Address.valueOf(
1340 IPv6.getLinkLocalAddress(config.getDeviceMac(deviceId).toBytes()));
1341
Saurav Das261c3002017-06-13 15:35:54 -07001342 if (config.isPairedEdge(deviceId)) {
1343 pairRouterIpv4 = config.getRouterIpv4(config.getPairDeviceId(deviceId));
1344 pairRouterIpv6 = config.getRouterIpv6(config.getPairDeviceId(deviceId));
1345 }
Charles Chan319d1a22015-11-03 10:42:14 -08001346 } catch (DeviceConfigNotFoundException e) {
Danny Chang44a7b952020-09-08 15:27:04 -07001347 log.warn(e.getMessage() + " Aborting manageIpPunts.");
Charles Chan319d1a22015-11-03 10:42:14 -08001348 return;
1349 }
1350
Danny Chang44a7b952020-09-08 15:27:04 -07001351 if (request && !srManager.mastershipService.isLocalMaster(deviceId)) {
Saurav Dasc28b3432015-10-30 17:45:38 -07001352 log.debug("Not installing port-IP punts - not the master for dev:{} ",
1353 deviceId);
1354 return;
1355 }
Danny Chang44a7b952020-09-08 15:27:04 -07001356
Pier Ventreadb4ae62016-11-23 09:57:42 -08001357 Set<IpAddress> allIps = new HashSet<>(config.getPortIPs(deviceId));
1358 allIps.add(routerIpv4);
1359 if (routerIpv6 != null) {
1360 allIps.add(routerIpv6);
Charles Chanf0f7b5c2018-08-29 14:55:53 -07001361 allIps.add(routerLinkLocalIpv6);
Pier Ventreadb4ae62016-11-23 09:57:42 -08001362 }
Saurav Das261c3002017-06-13 15:35:54 -07001363 if (pairRouterIpv4 != null) {
1364 allIps.add(pairRouterIpv4);
1365 }
1366 if (pairRouterIpv6 != null) {
1367 allIps.add(pairRouterIpv6);
1368 }
Pier Ventreadb4ae62016-11-23 09:57:42 -08001369 for (IpAddress ipaddr : allIps) {
Danny Chang44a7b952020-09-08 15:27:04 -07001370 manageSingleIpPunts(deviceId, ipaddr, request);
Jonghwan Hyune5ef7622017-08-25 17:48:36 -07001371 }
1372 }
Charles Chan2d0bbcd2017-01-09 11:45:08 -08001373
Jonghwan Hyune5ef7622017-08-25 17:48:36 -07001374 /**
Danny Chang44a7b952020-09-08 15:27:04 -07001375 * Creates or removes a forwarding objective ( packet-request ) to punt all IP packets, destined to the
Jonghwan Hyune5ef7622017-08-25 17:48:36 -07001376 * specified IP address, which should be router's port IP address.
1377 *
1378 * @param deviceId the switch dpid for the router
1379 * @param ipAddress the IP address of the router's port
Danny Chang44a7b952020-09-08 15:27:04 -07001380 * @param request true to create a packet request, false to remove
Jonghwan Hyune5ef7622017-08-25 17:48:36 -07001381 */
Danny Chang44a7b952020-09-08 15:27:04 -07001382 void manageSingleIpPunts(DeviceId deviceId, IpAddress ipAddress, boolean request) {
Jonghwan Hyune5ef7622017-08-25 17:48:36 -07001383 TrafficSelector.Builder sbuilder = buildIpSelectorFromIpAddress(ipAddress);
1384 Optional<DeviceId> optDeviceId = Optional.of(deviceId);
1385
Danny Chang44a7b952020-09-08 15:27:04 -07001386 if (request) {
1387 srManager.packetService.requestPackets(sbuilder.build(),
1388 PacketPriority.CONTROL, srManager.appId, optDeviceId);
1389 } else {
1390 srManager.packetService.cancelPackets(sbuilder.build(),
1391 PacketPriority.CONTROL, srManager.appId, optDeviceId);
Saurav Das9f1c42e2015-10-23 10:51:11 -07001392 }
sangho80f11cb2015-04-01 13:05:26 -07001393 }
1394
piera9941192019-04-24 16:12:47 +02001395 // Method for building an IPv4 selector
1396 private TrafficSelector.Builder buildIpv4Selector() {
1397 TrafficSelector.Builder selectorBuilder = DefaultTrafficSelector.builder();
1398 selectorBuilder.matchEthType(Ethernet.TYPE_IPV4);
1399 return selectorBuilder;
1400 }
1401
1402 // Method for building an IPv6 selector
1403 private TrafficSelector.Builder buildIpv6Selector() {
1404 TrafficSelector.Builder selectorBuilder = DefaultTrafficSelector.builder();
1405 selectorBuilder.matchEthType(Ethernet.TYPE_IPV6);
1406 return selectorBuilder;
1407 }
1408
1409 // Method for building an IPv4 or IPv6 selector from an IP address
Pier Ventreadb4ae62016-11-23 09:57:42 -08001410 private TrafficSelector.Builder buildIpSelectorFromIpAddress(IpAddress addressToMatch) {
1411 return buildIpSelectorFromIpPrefix(addressToMatch.toIpPrefix());
1412 }
1413
piera9941192019-04-24 16:12:47 +02001414 // Method for building an IPv4 or IPv6 selector from an IP prefix
Pier Ventreadb4ae62016-11-23 09:57:42 -08001415 private TrafficSelector.Builder buildIpSelectorFromIpPrefix(IpPrefix prefixToMatch) {
1416 TrafficSelector.Builder selectorBuilder = DefaultTrafficSelector.builder();
Pier Ventre229fd0b2016-10-31 16:49:19 -07001417 // If the prefix is IPv4
Pier Ventreadb4ae62016-11-23 09:57:42 -08001418 if (prefixToMatch.isIp4()) {
1419 selectorBuilder.matchEthType(Ethernet.TYPE_IPV4);
1420 selectorBuilder.matchIPDst(prefixToMatch.getIp4Prefix());
1421 return selectorBuilder;
1422 }
Pier Ventre229fd0b2016-10-31 16:49:19 -07001423 // If the prefix is IPv6
Pier Ventreadb4ae62016-11-23 09:57:42 -08001424 selectorBuilder.matchEthType(Ethernet.TYPE_IPV6);
1425 selectorBuilder.matchIPv6Dst(prefixToMatch.getIp6Prefix());
1426 return selectorBuilder;
1427 }
1428
1429 /**
Pier Luigib9632ba2017-01-12 18:14:58 -08001430 * Creates forwarding objectives to punt ARP and NDP packets, to the controller.
1431 * Furthermore, these are applied only by the master instance. Deferred actions
1432 * are not cleared such that packets can be flooded in the cross connect use case
1433 *
1434 * @param deviceId the switch dpid for the router
1435 */
Charles Chan3ed34d82017-06-22 18:03:14 -07001436 void populateArpNdpPunts(DeviceId deviceId) {
Pier Ventre229fd0b2016-10-31 16:49:19 -07001437 // We are not the master just skip.
Pier Luigib9632ba2017-01-12 18:14:58 -08001438 if (!srManager.mastershipService.isLocalMaster(deviceId)) {
1439 log.debug("Not installing ARP/NDP punts - not the master for dev:{} ",
1440 deviceId);
1441 return;
1442 }
1443
Charles Chan3ed34d82017-06-22 18:03:14 -07001444 ForwardingObjective fwdObj;
Pier Luigib9632ba2017-01-12 18:14:58 -08001445 // We punt all ARP packets towards the controller.
Charles Chanef8d12e2017-12-05 21:07:38 -08001446 fwdObj = arpFwdObjective(null, true, ARP_NDP_PRIORITY)
Pier Luigib9632ba2017-01-12 18:14:58 -08001447 .add(new ObjectiveContext() {
1448 @Override
1449 public void onError(Objective objective, ObjectiveError error) {
Charles Chan3ed34d82017-06-22 18:03:14 -07001450 log.warn("Failed to install forwarding objective to punt ARP to {}: {}",
Pier Luigib9632ba2017-01-12 18:14:58 -08001451 deviceId, error);
1452 }
1453 });
Charles Chan3ed34d82017-06-22 18:03:14 -07001454 srManager.flowObjectiveService.forward(deviceId, fwdObj);
Pier Luigib9632ba2017-01-12 18:14:58 -08001455
Charles Chanf0f7b5c2018-08-29 14:55:53 -07001456 if (isIpv6Configured(deviceId)) {
1457 // We punt all NDP packets towards the controller.
1458 ndpFwdObjective(null, true, ARP_NDP_PRIORITY).forEach(builder -> {
1459 ForwardingObjective obj = builder.add(new ObjectiveContext() {
1460 @Override
1461 public void onError(Objective objective, ObjectiveError error) {
1462 log.warn("Failed to install forwarding objective to punt NDP to {}: {}",
1463 deviceId, error);
1464 }
1465 });
1466 srManager.flowObjectiveService.forward(deviceId, obj);
Charles Chan051490d2018-01-11 11:48:18 -08001467 });
Charles Chanf0f7b5c2018-08-29 14:55:53 -07001468 }
Charles Chan3ed34d82017-06-22 18:03:14 -07001469
Saurav Dasec683dc2018-04-27 18:42:30 -07001470 srManager.getPairLocalPort(deviceId).ifPresent(port -> {
Charles Chan3ed34d82017-06-22 18:03:14 -07001471 ForwardingObjective pairFwdObj;
1472 // Do not punt ARP packets from pair port
1473 pairFwdObj = arpFwdObjective(port, false, PacketPriority.CONTROL.priorityValue() + 1)
1474 .add(new ObjectiveContext() {
1475 @Override
1476 public void onError(Objective objective, ObjectiveError error) {
1477 log.warn("Failed to install forwarding objective to ignore ARP to {}: {}",
1478 deviceId, error);
1479 }
1480 });
1481 srManager.flowObjectiveService.forward(deviceId, pairFwdObj);
1482
Charles Chanf0f7b5c2018-08-29 14:55:53 -07001483 if (isIpv6Configured(deviceId)) {
1484 // Do not punt NDP packets from pair port
1485 ndpFwdObjective(port, false, PacketPriority.CONTROL.priorityValue() + 1).forEach(builder -> {
1486 ForwardingObjective obj = builder.add(new ObjectiveContext() {
Charles Chan3ed34d82017-06-22 18:03:14 -07001487 @Override
1488 public void onError(Objective objective, ObjectiveError error) {
Charles Chanf0f7b5c2018-08-29 14:55:53 -07001489 log.warn("Failed to install forwarding objective to ignore ARP to {}: {}",
Charles Chan3ed34d82017-06-22 18:03:14 -07001490 deviceId, error);
1491 }
1492 });
Charles Chanf0f7b5c2018-08-29 14:55:53 -07001493 srManager.flowObjectiveService.forward(deviceId, obj);
1494 });
1495
1496 // Do not forward DAD packets from pair port
1497 pairFwdObj = dad6FwdObjective(port, PacketPriority.CONTROL.priorityValue() + 2)
1498 .add(new ObjectiveContext() {
1499 @Override
1500 public void onError(Objective objective, ObjectiveError error) {
1501 log.warn("Failed to install forwarding objective to drop DAD to {}: {}",
1502 deviceId, error);
1503 }
1504 });
1505 srManager.flowObjectiveService.forward(deviceId, pairFwdObj);
1506 }
Charles Chan3ed34d82017-06-22 18:03:14 -07001507 });
Pier Luigib9632ba2017-01-12 18:14:58 -08001508 }
1509
Charles Chan3ed34d82017-06-22 18:03:14 -07001510 private ForwardingObjective.Builder fwdObjBuilder(TrafficSelector selector,
1511 TrafficTreatment treatment, int priority) {
Pier Luigib9632ba2017-01-12 18:14:58 -08001512 return DefaultForwardingObjective.builder()
Charles Chan3ed34d82017-06-22 18:03:14 -07001513 .withPriority(priority)
Pier Luigib9632ba2017-01-12 18:14:58 -08001514 .withSelector(selector)
1515 .fromApp(srManager.appId)
1516 .withFlag(ForwardingObjective.Flag.VERSATILE)
Charles Chan3ed34d82017-06-22 18:03:14 -07001517 .withTreatment(treatment)
Pier Luigib9632ba2017-01-12 18:14:58 -08001518 .makePermanent();
1519 }
1520
Charles Chan3ed34d82017-06-22 18:03:14 -07001521 private ForwardingObjective.Builder arpFwdObjective(PortNumber port, boolean punt, int priority) {
Pier Luigib9632ba2017-01-12 18:14:58 -08001522 TrafficSelector.Builder sBuilder = DefaultTrafficSelector.builder();
1523 sBuilder.matchEthType(TYPE_ARP);
Charles Chan3ed34d82017-06-22 18:03:14 -07001524 if (port != null) {
1525 sBuilder.matchInPort(port);
1526 }
Pier Luigib9632ba2017-01-12 18:14:58 -08001527
Charles Chan3ed34d82017-06-22 18:03:14 -07001528 TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder();
1529 if (punt) {
1530 tBuilder.punt();
1531 }
1532 return fwdObjBuilder(sBuilder.build(), tBuilder.build(), priority);
Pier Luigib9632ba2017-01-12 18:14:58 -08001533 }
1534
Charles Chan051490d2018-01-11 11:48:18 -08001535 private Set<ForwardingObjective.Builder> ndpFwdObjective(PortNumber port, boolean punt, int priority) {
1536 Set<ForwardingObjective.Builder> result = Sets.newHashSet();
Pier Luigib9632ba2017-01-12 18:14:58 -08001537
Charles Chan051490d2018-01-11 11:48:18 -08001538 Lists.newArrayList(NEIGHBOR_SOLICITATION, NEIGHBOR_ADVERTISEMENT, ROUTER_SOLICITATION, ROUTER_ADVERTISEMENT)
1539 .forEach(type -> {
1540 TrafficSelector.Builder sBuilder = DefaultTrafficSelector.builder();
1541 sBuilder.matchEthType(TYPE_IPV6)
1542 .matchIPProtocol(PROTOCOL_ICMP6)
1543 .matchIcmpv6Type(type);
1544 if (port != null) {
1545 sBuilder.matchInPort(port);
1546 }
1547
1548 TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder();
1549 if (punt) {
1550 tBuilder.punt();
1551 }
1552
1553 result.add(fwdObjBuilder(sBuilder.build(), tBuilder.build(), priority));
1554 });
1555
1556 return result;
Charles Chan3ed34d82017-06-22 18:03:14 -07001557 }
1558
1559 private ForwardingObjective.Builder dad6FwdObjective(PortNumber port, int priority) {
1560 TrafficSelector.Builder sBuilder = DefaultTrafficSelector.builder();
1561 sBuilder.matchEthType(TYPE_IPV6)
Charles Chane6bda752017-08-07 12:39:03 -07001562 .matchIPv6Src(Ip6Address.ZERO.toIpPrefix());
1563 // TODO CORD-1672 Fix this when OFDPA can distinguish ::/0 and ::/128 correctly
1564 // .matchIPProtocol(PROTOCOL_ICMP6)
1565 // .matchIcmpv6Type(NEIGHBOR_SOLICITATION);
Charles Chan3ed34d82017-06-22 18:03:14 -07001566 if (port != null) {
1567 sBuilder.matchInPort(port);
1568 }
1569
1570 TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder();
1571 tBuilder.wipeDeferred();
1572 return fwdObjBuilder(sBuilder.build(), tBuilder.build(), priority);
Pier Luigib9632ba2017-01-12 18:14:58 -08001573 }
1574
1575 /**
Charles Chan155ec442018-09-16 14:30:19 -07001576 * Block given prefix in routing table.
Charles Chanf4586112015-11-09 16:37:23 -08001577 *
Andrea Campanella60ce2222018-04-30 11:48:55 +02001578 * @param address the address to block
1579 * @param deviceId switch ID to set the rules
1580 */
1581 void populateDefaultRouteBlackhole(DeviceId deviceId, IpPrefix address) {
1582 updateDefaultRouteBlackhole(deviceId, address, true);
1583 }
1584
1585 /**
Charles Chan155ec442018-09-16 14:30:19 -07001586 * Unblock given prefix in routing table.
Andrea Campanella60ce2222018-04-30 11:48:55 +02001587 *
1588 * @param address the address to block
1589 * @param deviceId switch ID to set the rules
1590 */
1591 void removeDefaultRouteBlackhole(DeviceId deviceId, IpPrefix address) {
1592 updateDefaultRouteBlackhole(deviceId, address, false);
1593 }
1594
1595 private void updateDefaultRouteBlackhole(DeviceId deviceId, IpPrefix address, boolean install) {
1596 try {
1597 if (srManager.deviceConfiguration.isEdgeDevice(deviceId)) {
1598
1599 TrafficSelector.Builder sbuilder = DefaultTrafficSelector.builder();
1600 if (address.isIp4()) {
1601 sbuilder.matchIPDst(address);
1602 sbuilder.matchEthType(EthType.EtherType.IPV4.ethType().toShort());
1603 } else {
1604 sbuilder.matchIPv6Dst(address);
1605 sbuilder.matchEthType(EthType.EtherType.IPV6.ethType().toShort());
1606 }
1607
1608 TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder();
Andrea Campanella60ce2222018-04-30 11:48:55 +02001609 tBuilder.wipeDeferred();
1610
1611 ForwardingObjective.Builder fob = DefaultForwardingObjective.builder();
1612 fob.withFlag(Flag.SPECIFIC)
1613 .withSelector(sbuilder.build())
1614 .withTreatment(tBuilder.build())
1615 .withPriority(getPriorityFromPrefix(address))
1616 .fromApp(srManager.appId)
1617 .makePermanent();
1618
1619 log.debug("{} blackhole forwarding objectives for dev: {}",
1620 install ? "Installing" : "Removing", deviceId);
1621 ObjectiveContext context = new DefaultObjectiveContext(
1622 (objective) -> log.debug("Forward for {} {}", deviceId,
1623 install ? "installed" : "removed"),
1624 (objective, error) -> log.warn("Failed to {} forward for {}: {}",
1625 install ? "install" : "remove", deviceId, error));
1626 if (install) {
1627 srManager.flowObjectiveService.forward(deviceId, fob.add(context));
1628 } else {
1629 srManager.flowObjectiveService.forward(deviceId, fob.remove(context));
1630 }
1631 }
1632 } catch (DeviceConfigNotFoundException e) {
1633 log.info("Not populating blackhole for un-configured device {}", deviceId);
1634 }
1635
1636 }
1637
1638 /**
1639 * Populates a forwarding objective to send packets that miss other high
1640 * priority Bridging Table entries to a group that contains all ports of
1641 * its subnet.
1642 *
Charles Chanf4586112015-11-09 16:37:23 -08001643 * @param deviceId switch ID to set the rules
1644 */
Charles Chan3ed34d82017-06-22 18:03:14 -07001645 void populateSubnetBroadcastRule(DeviceId deviceId) {
Charles Chan90772a72017-02-08 15:52:08 -08001646 srManager.getVlanPortMap(deviceId).asMap().forEach((vlanId, ports) -> {
Jonghwan Hyune5ef7622017-08-25 17:48:36 -07001647 updateSubnetBroadcastRule(deviceId, vlanId, true);
Charles Chanf4586112015-11-09 16:37:23 -08001648 });
1649 }
1650
Jonghwan Hyune5ef7622017-08-25 17:48:36 -07001651 /**
1652 * Creates or removes a forwarding objective to broadcast packets to its subnet.
1653 * @param deviceId switch ID to set the rule
1654 * @param vlanId vlan ID to specify the subnet
1655 * @param install true to install the rule, false to revoke the rule
1656 */
1657 void updateSubnetBroadcastRule(DeviceId deviceId, VlanId vlanId, boolean install) {
1658 int nextId = srManager.getVlanNextObjectiveId(deviceId, vlanId);
1659
1660 if (nextId < 0) {
1661 log.error("Cannot install vlan {} broadcast rule in dev:{} due"
1662 + " to vlanId:{} or nextId:{}", vlanId, deviceId, vlanId, nextId);
1663 return;
1664 }
1665
1666 // Driver should treat objective with MacAddress.NONE as the
1667 // subnet broadcast rule
1668 TrafficSelector.Builder sbuilder = DefaultTrafficSelector.builder();
1669 sbuilder.matchVlanId(vlanId);
1670 sbuilder.matchEthDst(MacAddress.NONE);
1671
1672 ForwardingObjective.Builder fob = DefaultForwardingObjective.builder();
1673 fob.withFlag(Flag.SPECIFIC)
1674 .withSelector(sbuilder.build())
1675 .nextStep(nextId)
1676 .withPriority(SegmentRoutingService.FLOOD_PRIORITY)
1677 .fromApp(srManager.appId)
1678 .makePermanent();
1679 ObjectiveContext context = new DefaultObjectiveContext(
1680 (objective) -> log.debug("Vlan broadcast rule for {} populated", vlanId),
1681 (objective, error) ->
1682 log.warn("Failed to populate vlan broadcast rule for {}: {}", vlanId, error));
1683
1684 if (install) {
1685 srManager.flowObjectiveService.forward(deviceId, fob.add(context));
1686 } else {
1687 srManager.flowObjectiveService.forward(deviceId, fob.remove(context));
1688 }
1689 }
1690
Charles Chan82ab1932016-01-30 23:22:37 -08001691 private int getPriorityFromPrefix(IpPrefix prefix) {
1692 return (prefix.isIp4()) ?
1693 2000 * prefix.prefixLength() + SegmentRoutingService.MIN_IP_PRIORITY :
1694 500 * prefix.prefixLength() + SegmentRoutingService.MIN_IP_PRIORITY;
Srikanth Vavilapalli8c83f1d2015-05-22 13:47:31 -07001695 }
Jonghwan Hyune5ef7622017-08-25 17:48:36 -07001696
1697 /**
1698 * Update Forwarding objective for each host and IP address connected to given port.
1699 * And create corresponding Simple Next objective if it does not exist.
1700 * Applied only when populating Forwarding objective
1701 * @param deviceId switch ID to set the rule
1702 * @param portNumber port number
1703 * @param prefix IP prefix of the route
1704 * @param hostMac MAC address of the next hop
1705 * @param vlanId Vlan ID of the port
1706 * @param popVlan true to pop vlan tag in TrafficTreatment
1707 * @param install true to populate the forwarding objective, false to revoke
1708 */
1709 void updateFwdObj(DeviceId deviceId, PortNumber portNumber, IpPrefix prefix, MacAddress hostMac,
1710 VlanId vlanId, boolean popVlan, boolean install) {
1711 ForwardingObjective.Builder fob;
1712 TrafficSelector.Builder sbuilder = buildIpSelectorFromIpPrefix(prefix);
1713 MacAddress deviceMac;
1714 try {
1715 deviceMac = config.getDeviceMac(deviceId);
1716 } catch (DeviceConfigNotFoundException e) {
1717 log.warn(e.getMessage() + " Aborting updateFwdObj.");
1718 return;
1719 }
1720
1721 TrafficTreatment.Builder tbuilder = DefaultTrafficTreatment.builder();
1722 tbuilder.deferred()
1723 .setEthDst(hostMac)
1724 .setEthSrc(deviceMac)
1725 .setOutput(portNumber);
1726
1727 TrafficSelector.Builder mbuilder = DefaultTrafficSelector.builder();
1728
1729 if (!popVlan) {
pierventre50e1bb82020-12-14 19:31:03 +01001730 mbuilder.matchVlanId(vlanId);
Jonghwan Hyune5ef7622017-08-25 17:48:36 -07001731 tbuilder.setVlanId(vlanId);
1732 } else {
1733 mbuilder.matchVlanId(vlanId);
pierventre50e1bb82020-12-14 19:31:03 +01001734 tbuilder.popVlan();
Jonghwan Hyune5ef7622017-08-25 17:48:36 -07001735 }
1736
1737 // if the objective is to revoke an existing rule, and for some reason
1738 // the next-objective does not exist, then a new one should not be created
1739 int portNextObjId = srManager.getPortNextObjectiveId(deviceId, portNumber,
1740 tbuilder.build(), mbuilder.build(), install);
1741 if (portNextObjId == -1) {
1742 // Warning log will come from getPortNextObjective method
1743 return;
1744 }
1745
1746 fob = DefaultForwardingObjective.builder().withSelector(sbuilder.build())
1747 .nextStep(portNextObjId).fromApp(srManager.appId).makePermanent()
1748 .withPriority(getPriorityFromPrefix(prefix)).withFlag(ForwardingObjective.Flag.SPECIFIC);
1749
1750 ObjectiveContext context = new DefaultObjectiveContext(
1751 (objective) -> log.debug("IP rule for route {} {}", prefix, install ? "installed" : "revoked"),
1752 (objective, error) ->
1753 log.warn("Failed to {} IP rule for route {}: {}",
1754 install ? "install" : "revoke", prefix, error));
1755 srManager.flowObjectiveService.forward(deviceId, install ? fob.add(context) : fob.remove(context));
1756
1757 if (!install) {
Shibu Vijayakumar632dd642018-03-01 15:45:59 -08001758 if (!srManager.getVlanPortMap(deviceId).containsKey(vlanId) ||
1759 !srManager.getVlanPortMap(deviceId).get(vlanId).contains(portNumber)) {
1760 DefaultGroupHandler grpHandler = srManager.getGroupHandler(deviceId);
1761 if (grpHandler == null) {
1762 log.warn("updateFwdObj: groupHandler for device {} not found", deviceId);
1763 } else {
1764 // Remove L3UG for the given port and host
1765 grpHandler.removeGroupFromPort(portNumber, tbuilder.build(), mbuilder.build());
1766 }
Jonghwan Hyune5ef7622017-08-25 17:48:36 -07001767 }
1768 }
1769 }
Charles Chanf17f66b2018-02-26 21:33:25 -08001770
1771 /**
1772 * Checks if there is other enabled port within the given VLAN on the given device.
1773 *
1774 * @param deviceId device ID
1775 * @param vlanId VLAN ID
1776 * @return true if there is no more port enabled within the given VLAN on the given device
1777 */
1778 boolean noMoreEnabledPort(DeviceId deviceId, VlanId vlanId) {
1779 Set<ConnectPoint> enabledPorts = srManager.deviceService.getPorts(deviceId).stream()
1780 .filter(Port::isEnabled)
1781 .map(port -> new ConnectPoint(port.element().id(), port.number()))
1782 .collect(Collectors.toSet());
1783
1784 return enabledPorts.stream().noneMatch(cp ->
1785 // Given vlanId is included in the vlan-tagged configuration
Charles Chan098ca202018-05-01 11:50:20 -07001786 srManager.interfaceService.getTaggedVlanId(cp).contains(vlanId) ||
pieraac79e92019-10-04 15:40:34 +02001787 // Given vlanId is INTERNAL_VLAN or PSEUDOWIRE_VLAN and the interface is not configured
Charles Chan098ca202018-05-01 11:50:20 -07001788 (srManager.interfaceService.getTaggedVlanId(cp).isEmpty() && srManager.getInternalVlanId(cp) == null &&
pieraac79e92019-10-04 15:40:34 +02001789 (vlanId.equals(srManager.getDefaultInternalVlan()) || vlanId.equals(srManager.getPwTransportVlan()))) ||
Charles Chanf17f66b2018-02-26 21:33:25 -08001790 // interface is configured and either vlan-untagged or vlan-native matches given vlanId
1791 (srManager.getInternalVlanId(cp) != null && srManager.getInternalVlanId(cp).equals(vlanId))
1792 );
1793 }
Jonghwan Hyun9aaa34f2018-04-09 09:40:50 -07001794
1795 /**
1796 * Returns a forwarding objective builder for egress forwarding rules.
1797 * <p>
1798 * The forwarding objective installs flow rules to egress pipeline to push
1799 * two vlan headers with given inner, outer vlan ids and outer tpid.
1800 *
1801 * @param portNumber port where the next hop attaches to
1802 * @param dummyVlanId vlan ID of the packet to match
1803 * @param innerVlan inner vlan ID of the next hop
1804 * @param outerVlan outer vlan ID of the next hop
1805 * @param outerTpid outer TPID of the next hop
1806 * @return forwarding objective builder
1807 */
1808 private ForwardingObjective.Builder egressFwdObjBuilder(PortNumber portNumber, VlanId dummyVlanId,
1809 VlanId innerVlan, VlanId outerVlan, EthType outerTpid) {
1810 TrafficSelector.Builder sbuilder = DefaultTrafficSelector.builder();
1811 sbuilder.matchVlanId(dummyVlanId);
1812 TrafficTreatment.Builder tbuilder = DefaultTrafficTreatment.builder();
1813 tbuilder.setOutput(portNumber).setVlanId(innerVlan);
1814
1815 if (outerTpid.equals(EthType.EtherType.QINQ.ethType())) {
1816 tbuilder.pushVlan(outerTpid);
1817 } else {
1818 tbuilder.pushVlan();
1819 }
1820
1821 tbuilder.setVlanId(outerVlan);
1822 return DefaultForwardingObjective.builder()
1823 .withSelector(sbuilder.build())
1824 .withTreatment(tbuilder.build())
1825 .fromApp(srManager.appId)
1826 .makePermanent()
1827 .withPriority(DEFAULT_PRIORITY)
1828 .withFlag(ForwardingObjective.Flag.EGRESS);
1829 }
1830
1831 /**
1832 * Populates IP rules for a route that has double-tagged next hop.
1833 *
1834 * @param deviceId device ID of the device that next hop attaches to
1835 * @param prefix IP prefix of the route
1836 * @param hostMac MAC address of the next hop
Jonghwan Hyun9aaa34f2018-04-09 09:40:50 -07001837 * @param innerVlan inner Vlan ID of the next hop
1838 * @param outerVlan outer Vlan ID of the next hop
1839 * @param outerTpid outer TPID of the next hop
1840 * @param outPort port where the next hop attaches to
1841 */
Charles Chan61c086d2019-07-26 17:46:15 -07001842 void populateDoubleTaggedRoute(DeviceId deviceId, IpPrefix prefix, MacAddress hostMac,
Jonghwan Hyun9aaa34f2018-04-09 09:40:50 -07001843 VlanId innerVlan, VlanId outerVlan, EthType outerTpid, PortNumber outPort) {
1844 ForwardingObjective.Builder fwdBuilder;
1845 log.debug("Populate direct routing entry for double-tagged host route {} at {}:{}",
1846 prefix, deviceId, outPort);
1847
Jonghwan Hyun9aaa34f2018-04-09 09:40:50 -07001848 try {
Charles Chan61c086d2019-07-26 17:46:15 -07001849 fwdBuilder = routingFwdObjBuilder(deviceId, prefix, hostMac, outerVlan, outPort, innerVlan, outerTpid,
1850 true, false);
Jonghwan Hyun9aaa34f2018-04-09 09:40:50 -07001851 } catch (DeviceConfigNotFoundException e) {
1852 log.error(e.getMessage() + " Aborting populateDoubleTaggedRoute");
1853 return;
1854 }
1855 if (fwdBuilder == null) {
1856 log.error("Aborting double-tagged host routing table entry due to error for dev:{} route:{}",
1857 deviceId, prefix);
1858 return;
1859 }
1860
Jonghwan Hyun9aaa34f2018-04-09 09:40:50 -07001861 int nextId = fwdBuilder.add().nextId();
1862 DefaultObjectiveContext context = new DefaultObjectiveContext(objective -> {
1863 log.debug("Direct routing rule for double-tagged host route {} populated. nextId={}", prefix, nextId);
Jonghwan Hyun9aaa34f2018-04-09 09:40:50 -07001864 }, (objective, error) ->
1865 log.warn("Failed to populate direct routing rule for double-tagged host route {}: {}", prefix, error)
1866 );
1867 srManager.flowObjectiveService.forward(deviceId, fwdBuilder.add(context));
1868 rulePopulationCounter.incrementAndGet();
1869 }
1870
1871 /**
1872 * Revokes IP rules for a route that has double-tagged next hop.
1873 *
1874 * @param deviceId device ID of the device that next hop attaches to
1875 * @param prefix IP prefix of the route
1876 * @param hostMac MAC address of the next hop
Jonghwan Hyun9aaa34f2018-04-09 09:40:50 -07001877 * @param innerVlan inner Vlan ID of the next hop
1878 * @param outerVlan outer Vlan ID of the next hop
1879 * @param outerTpid outer TPID of the next hop
1880 * @param outPort port where the next hop attaches to
1881 */
1882 void revokeDoubleTaggedRoute(DeviceId deviceId, IpPrefix prefix, MacAddress hostMac,
Charles Chan61c086d2019-07-26 17:46:15 -07001883 VlanId innerVlan, VlanId outerVlan, EthType outerTpid, PortNumber outPort) {
1884 ForwardingObjective.Builder fwdBuilder;
1885 log.debug("Revoking direct routing entry for double-tagged host route {} at {}:{}",
1886 prefix, deviceId, outPort);
Jonghwan Hyun9aaa34f2018-04-09 09:40:50 -07001887
Charles Chan61c086d2019-07-26 17:46:15 -07001888 try {
1889 fwdBuilder = routingFwdObjBuilder(deviceId, prefix, hostMac, outerVlan, outPort, innerVlan, outerTpid,
1890 true, true);
1891 } catch (DeviceConfigNotFoundException e) {
1892 log.error(e.getMessage() + " Aborting revokeDoubleTaggedRoute");
Jonghwan Hyun9aaa34f2018-04-09 09:40:50 -07001893 return;
1894 }
Charles Chan61c086d2019-07-26 17:46:15 -07001895 if (fwdBuilder == null) {
1896 log.error("Aborting double-tagged host routing table entry due to error for dev:{} route:{}",
1897 deviceId, prefix);
1898 return;
1899 }
1900
1901 int nextId = fwdBuilder.remove().nextId();
Jonghwan Hyun9aaa34f2018-04-09 09:40:50 -07001902 DefaultObjectiveContext context = new DefaultObjectiveContext(objective -> {
Charles Chan61c086d2019-07-26 17:46:15 -07001903 log.debug("Direct routing rule for double-tagged host route {} revoked. nextId={}", prefix, nextId);
1904
1905 // Try to remove next objective as well
1906 ImmutablePair<TrafficTreatment, TrafficSelector> treatmentAndMeta;
1907 try {
1908 treatmentAndMeta = getTreatmentAndMeta(deviceId, hostMac, outerVlan, outPort, innerVlan, outerTpid);
1909 } catch (DeviceConfigNotFoundException e) {
1910 log.error(e.getMessage() + " Aborting revokeDoubleTaggedRoute");
1911 return;
1912 }
1913
1914 if (treatmentAndMeta == null) {
1915 // Warning log will come from getTreatmentAndMeta method
1916 return;
1917 }
1918
1919 DefaultGroupHandler groupHandler = srManager.getGroupHandler(deviceId);
1920 if (groupHandler == null) {
1921 log.warn("Failed to revoke direct routing rule for double-tagged host route {}: " +
1922 "group handler not found for {}", prefix, deviceId);
1923 return;
1924 }
1925 groupHandler.removeGroupFromPort(outPort, treatmentAndMeta.getLeft(), treatmentAndMeta.getRight());
1926
1927 }, (objective, error) ->
1928 log.warn("Failed to revoke direct routing rule for double-tagged host route {}: {}", prefix, error)
1929 );
1930 srManager.flowObjectiveService.forward(deviceId, fwdBuilder.remove(context));
Jonghwan Hyun9aaa34f2018-04-09 09:40:50 -07001931 }
1932
Jonghwan Hyun671a7ab2018-04-30 09:27:21 -07001933 /**
1934 * Checks whether the specified port has IP configuration or not.
1935 *
1936 * @param cp ConnectPoint to check the existance of IP configuration
1937 * @return true if the port has IP configuration; false otherwise.
1938 */
1939 private boolean hasIPConfiguration(ConnectPoint cp) {
1940 Set<Interface> interfaces = srManager.interfaceService.getInterfacesByPort(cp);
1941 return interfaces.stream().anyMatch(intf -> intf.ipAddressesList().size() > 0);
1942 }
Saurav Das9bf49582018-08-13 15:34:26 -07001943
1944 /**
1945 * Updates filtering rules for unconfigured ports on all devices for which
1946 * this controller instance is master.
1947 *
1948 * @param pushVlan true if the filtering rule requires a push vlan action
1949 * @param oldVlanId the vlanId to be removed
1950 * @param newVlanId the vlanId to be added
1951 */
1952 void updateSpecialVlanFilteringRules(boolean pushVlan, VlanId oldVlanId,
1953 VlanId newVlanId) {
1954 for (Device dev : srManager.deviceService.getAvailableDevices()) {
1955 if (srManager.mastershipService.isLocalMaster(dev.id())) {
1956 for (Port p : srManager.deviceService.getPorts(dev.id())) {
1957 if (!hasIPConfiguration(new ConnectPoint(dev.id(), p.number()))
1958 && p.isEnabled()) {
1959 updateSinglePortFilters(dev.id(), p.number(), pushVlan,
1960 oldVlanId, false);
1961 updateSinglePortFilters(dev.id(), p.number(), pushVlan,
1962 newVlanId, true);
1963 }
1964 }
1965 }
1966 }
1967 }
1968
Charles Chanf0f7b5c2018-08-29 14:55:53 -07001969 private boolean isIpv6Configured(DeviceId deviceId) {
1970 boolean isIpv6Configured;
1971 try {
1972 isIpv6Configured = (config.getRouterIpv6(deviceId) != null);
1973 } catch (DeviceConfigNotFoundException e) {
1974 isIpv6Configured = false;
1975 }
1976 return isIpv6Configured;
1977 }
sangho80f11cb2015-04-01 13:05:26 -07001978}