blob: dae8a71e48d0cb431085fefd977ee42cf92ff555 [file] [log] [blame]
sangho80f11cb2015-04-01 13:05:26 -07001/*
Brian O'Connor43b53542016-04-09 01:19:45 -07002 * Copyright 2015-present Open Networking Laboratory
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;
Saurav Das4c35fc42015-11-20 15:27:53 -080019import org.onlab.packet.EthType;
sangho80f11cb2015-04-01 13:05:26 -070020import org.onlab.packet.Ethernet;
21import org.onlab.packet.Ip4Address;
Pier Ventreadb4ae62016-11-23 09:57:42 -080022import org.onlab.packet.Ip6Address;
23import org.onlab.packet.IpAddress;
sangho80f11cb2015-04-01 13:05:26 -070024import org.onlab.packet.IpPrefix;
25import org.onlab.packet.MacAddress;
sangho80f11cb2015-04-01 13:05:26 -070026import org.onlab.packet.MplsLabel;
Srikanth Vavilapalli64505482015-04-21 13:04:13 -070027import org.onlab.packet.VlanId;
Charles Chan10b0fb72017-02-02 16:20:42 -080028import org.onosproject.incubator.net.intf.Interface;
Charles Chanb7f75ac2016-01-11 18:28:54 -080029import org.onosproject.net.ConnectPoint;
Charles Chan1eaf4802016-04-18 13:44:03 -070030import org.onosproject.net.flowobjective.DefaultObjectiveContext;
Pier Luigib9632ba2017-01-12 18:14:58 -080031import org.onosproject.net.flowobjective.Objective;
Charles Chan1eaf4802016-04-18 13:44:03 -070032import org.onosproject.net.flowobjective.ObjectiveContext;
Pier Luigib9632ba2017-01-12 18:14:58 -080033import org.onosproject.net.flowobjective.ObjectiveError;
Charles Chan2d0bbcd2017-01-09 11:45:08 -080034import org.onosproject.net.packet.PacketPriority;
Saurav Dasd1872b02016-12-02 15:43:47 -080035import org.onosproject.segmentrouting.DefaultRoutingHandler.PortFilterInfo;
Charles Chan319d1a22015-11-03 10:42:14 -080036import org.onosproject.segmentrouting.config.DeviceConfigNotFoundException;
37import org.onosproject.segmentrouting.config.DeviceConfiguration;
Srikanth Vavilapalli37a461b2015-04-07 15:12:32 -070038import org.onosproject.segmentrouting.grouphandler.NeighborSet;
sangho80f11cb2015-04-01 13:05:26 -070039import org.onosproject.net.DeviceId;
Saurav Das7c305372015-10-28 12:39:42 -070040import org.onosproject.net.Port;
sangho80f11cb2015-04-01 13:05:26 -070041import org.onosproject.net.PortNumber;
sangho80f11cb2015-04-01 13:05:26 -070042import org.onosproject.net.flow.DefaultTrafficSelector;
43import org.onosproject.net.flow.DefaultTrafficTreatment;
sangho80f11cb2015-04-01 13:05:26 -070044import org.onosproject.net.flow.TrafficSelector;
45import org.onosproject.net.flow.TrafficTreatment;
Srikanth Vavilapalli64505482015-04-21 13:04:13 -070046import org.onosproject.net.flow.criteria.Criteria;
47import org.onosproject.net.flowobjective.DefaultFilteringObjective;
48import org.onosproject.net.flowobjective.DefaultForwardingObjective;
49import org.onosproject.net.flowobjective.FilteringObjective;
50import org.onosproject.net.flowobjective.ForwardingObjective;
51import org.onosproject.net.flowobjective.ForwardingObjective.Builder;
Saurav Das9f1c42e2015-10-23 10:51:11 -070052import org.onosproject.net.flowobjective.ForwardingObjective.Flag;
sangho80f11cb2015-04-01 13:05:26 -070053import org.slf4j.Logger;
54import org.slf4j.LoggerFactory;
55
56import java.util.ArrayList;
Pier Ventre229fd0b2016-10-31 16:49:19 -070057import java.util.Collection;
58import java.util.Collections;
Saurav Dasc28b3432015-10-30 17:45:38 -070059import java.util.HashSet;
sangho80f11cb2015-04-01 13:05:26 -070060import java.util.List;
Charles Chan2d0bbcd2017-01-09 11:45:08 -080061import java.util.Optional;
sangho80f11cb2015-04-01 13:05:26 -070062import java.util.Set;
sanghofb7c7292015-04-13 15:15:58 -070063import java.util.concurrent.atomic.AtomicLong;
Charles Chan10b0fb72017-02-02 16:20:42 -080064import java.util.stream.Collectors;
sangho80f11cb2015-04-01 13:05:26 -070065
66import static com.google.common.base.Preconditions.checkNotNull;
Pier Luigib9632ba2017-01-12 18:14:58 -080067import static org.onlab.packet.Ethernet.TYPE_ARP;
68import static org.onlab.packet.Ethernet.TYPE_IPV6;
69import static org.onlab.packet.ICMP6.NEIGHBOR_SOLICITATION;
70import static org.onlab.packet.IPv6.PROTOCOL_ICMP6;
Charles Chan10b0fb72017-02-02 16:20:42 -080071import static org.onosproject.segmentrouting.SegmentRoutingManager.INTERNAL_VLAN;
sangho80f11cb2015-04-01 13:05:26 -070072
Charles Chanb7f75ac2016-01-11 18:28:54 -080073/**
74 * Populator of segment routing flow rules.
75 */
sangho80f11cb2015-04-01 13:05:26 -070076public class RoutingRulePopulator {
Srikanth Vavilapalli64505482015-04-21 13:04:13 -070077 private static final Logger log = LoggerFactory
78 .getLogger(RoutingRulePopulator.class);
sangho80f11cb2015-04-01 13:05:26 -070079
sanghofb7c7292015-04-13 15:15:58 -070080 private AtomicLong rulePopulationCounter;
sangho9b169e32015-04-14 16:27:13 -070081 private SegmentRoutingManager srManager;
82 private DeviceConfiguration config;
Saurav Das9f1c42e2015-10-23 10:51:11 -070083
sangho80f11cb2015-04-01 13:05:26 -070084 /**
85 * Creates a RoutingRulePopulator object.
86 *
Thomas Vachuska8a075092015-04-15 18:20:08 -070087 * @param srManager segment routing manager reference
sangho80f11cb2015-04-01 13:05:26 -070088 */
89 public RoutingRulePopulator(SegmentRoutingManager srManager) {
90 this.srManager = srManager;
sangho9b169e32015-04-14 16:27:13 -070091 this.config = checkNotNull(srManager.deviceConfiguration);
sanghofb7c7292015-04-13 15:15:58 -070092 this.rulePopulationCounter = new AtomicLong(0);
93 }
94
95 /**
96 * Resets the population counter.
97 */
98 public void resetCounter() {
99 rulePopulationCounter.set(0);
100 }
101
102 /**
103 * Returns the number of rules populated.
Thomas Vachuska7cfc6202015-04-30 18:13:25 -0700104 *
105 * @return number of rules
sanghofb7c7292015-04-13 15:15:58 -0700106 */
107 public long getCounter() {
108 return rulePopulationCounter.get();
sangho80f11cb2015-04-01 13:05:26 -0700109 }
110
111 /**
Charles Chanddac7fd2016-10-27 14:19:48 -0700112 * Populates IP rules for a route that has direct connection to the
Srikanth Vavilapalli64505482015-04-21 13:04:13 -0700113 * switch.
sangho80f11cb2015-04-01 13:05:26 -0700114 *
Charles Chanddac7fd2016-10-27 14:19:48 -0700115 * @param deviceId device ID of the device that next hop attaches to
116 * @param prefix IP prefix of the route
117 * @param hostMac MAC address of the next hop
118 * @param outPort port where the next hop attaches to
sangho80f11cb2015-04-01 13:05:26 -0700119 */
Charles Chanddac7fd2016-10-27 14:19:48 -0700120 public void populateRoute(DeviceId deviceId, IpPrefix prefix,
sangho80f11cb2015-04-01 13:05:26 -0700121 MacAddress hostMac, PortNumber outPort) {
Charles Chanddac7fd2016-10-27 14:19:48 -0700122 log.debug("Populate IP table entry for route {} at {}:{}",
123 prefix, deviceId, outPort);
Charles Chanf4586112015-11-09 16:37:23 -0800124 ForwardingObjective.Builder fwdBuilder;
Charles Chan319d1a22015-11-03 10:42:14 -0800125 try {
Charles Chan18fa4252017-02-08 16:10:40 -0800126 fwdBuilder = routingFwdObjBuilder(
Charles Chanddac7fd2016-10-27 14:19:48 -0700127 deviceId, prefix, hostMac, outPort);
Charles Chan319d1a22015-11-03 10:42:14 -0800128 } catch (DeviceConfigNotFoundException e) {
129 log.warn(e.getMessage() + " Aborting populateIpRuleForHost.");
130 return;
131 }
Saurav Das07c74602016-04-27 18:35:50 -0700132 if (fwdBuilder == null) {
133 log.warn("Aborting host routing table entries due "
Charles Chanddac7fd2016-10-27 14:19:48 -0700134 + "to error for dev:{} route:{}", deviceId, prefix);
Saurav Das07c74602016-04-27 18:35:50 -0700135 return;
136 }
Charles Chan1eaf4802016-04-18 13:44:03 -0700137 ObjectiveContext context = new DefaultObjectiveContext(
Charles Chanddac7fd2016-10-27 14:19:48 -0700138 (objective) -> log.debug("IP rule for route {} populated", prefix),
Charles Chan1eaf4802016-04-18 13:44:03 -0700139 (objective, error) ->
Charles Chanddac7fd2016-10-27 14:19:48 -0700140 log.warn("Failed to populate IP rule for route {}: {}", prefix, error));
Charles Chan1eaf4802016-04-18 13:44:03 -0700141 srManager.flowObjectiveService.forward(deviceId, fwdBuilder.add(context));
Charles Chanf4586112015-11-09 16:37:23 -0800142 rulePopulationCounter.incrementAndGet();
143 }
144
Charles Chanb7f75ac2016-01-11 18:28:54 -0800145 /**
Charles Chanddac7fd2016-10-27 14:19:48 -0700146 * Removes IP rules for a route when the next hop is gone.
Charles Chanb7f75ac2016-01-11 18:28:54 -0800147 *
Charles Chanddac7fd2016-10-27 14:19:48 -0700148 * @param deviceId device ID of the device that next hop attaches to
149 * @param prefix IP prefix of the route
150 * @param hostMac MAC address of the next hop
151 * @param outPort port that next hop attaches to
Charles Chanb7f75ac2016-01-11 18:28:54 -0800152 */
Charles Chanddac7fd2016-10-27 14:19:48 -0700153 public void revokeRoute(DeviceId deviceId, IpPrefix prefix,
Charles Chanf4586112015-11-09 16:37:23 -0800154 MacAddress hostMac, PortNumber outPort) {
Charles Chanddac7fd2016-10-27 14:19:48 -0700155 log.debug("Revoke IP table entry for route {} at {}:{}",
156 prefix, deviceId, outPort);
Charles Chanf4586112015-11-09 16:37:23 -0800157 ForwardingObjective.Builder fwdBuilder;
158 try {
Charles Chan18fa4252017-02-08 16:10:40 -0800159 fwdBuilder = routingFwdObjBuilder(
Charles Chanddac7fd2016-10-27 14:19:48 -0700160 deviceId, prefix, hostMac, outPort);
Charles Chanf4586112015-11-09 16:37:23 -0800161 } catch (DeviceConfigNotFoundException e) {
162 log.warn(e.getMessage() + " Aborting revokeIpRuleForHost.");
163 return;
164 }
Charles Chanea702b12016-11-30 11:55:05 -0800165 if (fwdBuilder == null) {
166 log.warn("Aborting host routing table entries due "
167 + "to error for dev:{} route:{}", deviceId, prefix);
168 return;
169 }
Charles Chan1eaf4802016-04-18 13:44:03 -0700170 ObjectiveContext context = new DefaultObjectiveContext(
Charles Chanddac7fd2016-10-27 14:19:48 -0700171 (objective) -> log.debug("IP rule for route {} revoked", prefix),
Charles Chan1eaf4802016-04-18 13:44:03 -0700172 (objective, error) ->
Charles Chanddac7fd2016-10-27 14:19:48 -0700173 log.warn("Failed to revoke IP rule for route {}: {}", prefix, error));
Charles Chan1eaf4802016-04-18 13:44:03 -0700174 srManager.flowObjectiveService.forward(deviceId, fwdBuilder.remove(context));
Charles Chanf4586112015-11-09 16:37:23 -0800175 }
176
Charles Chanddac7fd2016-10-27 14:19:48 -0700177 /**
Charles Chan18fa4252017-02-08 16:10:40 -0800178 * Returns a forwarding objective builder for routing rules.
179 * <p>
180 * The forwarding objective routes packets destined to a given prefix to
181 * given port on given device with given destination MAC.
Charles Chanddac7fd2016-10-27 14:19:48 -0700182 *
183 * @param deviceId device ID
184 * @param prefix prefix that need to be routed
185 * @param hostMac MAC address of the nexthop
186 * @param outPort port where the nexthop attaches to
187 * @return forwarding objective builder
188 * @throws DeviceConfigNotFoundException if given device is not configured
189 */
Charles Chan18fa4252017-02-08 16:10:40 -0800190 private ForwardingObjective.Builder routingFwdObjBuilder(
Charles Chanddac7fd2016-10-27 14:19:48 -0700191 DeviceId deviceId, IpPrefix prefix,
Charles Chanf4586112015-11-09 16:37:23 -0800192 MacAddress hostMac, PortNumber outPort)
193 throws DeviceConfigNotFoundException {
194 MacAddress deviceMac;
195 deviceMac = config.getDeviceMac(deviceId);
Charles Chan319d1a22015-11-03 10:42:14 -0800196
Pier Ventre6b2c1b32016-12-09 17:26:04 -0800197 TrafficSelector.Builder sbuilder = buildIpSelectorFromIpPrefix(prefix);
Saurav Das2d94d312015-11-24 23:21:05 -0800198 TrafficSelector selector = sbuilder.build();
sangho80f11cb2015-04-01 13:05:26 -0700199
Charles Chanddac7fd2016-10-27 14:19:48 -0700200 TrafficTreatment.Builder tbuilder = DefaultTrafficTreatment.builder();
sangho27462c62015-05-14 00:39:53 -0700201 tbuilder.deferred()
202 .setEthDst(hostMac)
Charles Chan319d1a22015-11-03 10:42:14 -0800203 .setEthSrc(deviceMac)
sangho80f11cb2015-04-01 13:05:26 -0700204 .setOutput(outPort);
sangho80f11cb2015-04-01 13:05:26 -0700205 TrafficTreatment treatment = tbuilder.build();
Saurav Das2d94d312015-11-24 23:21:05 -0800206
207 // All forwarding is via Groups. Drivers can re-purpose to flow-actions if needed.
208 // for switch pipelines that need it, provide outgoing vlan as metadata
Charles Chan10b0fb72017-02-02 16:20:42 -0800209 VlanId untaggedVlan = srManager.getUntaggedVlanId(new ConnectPoint(deviceId, outPort));
210 VlanId outvlan = (untaggedVlan != null) ? untaggedVlan : INTERNAL_VLAN;
211
Saurav Das2d94d312015-11-24 23:21:05 -0800212 TrafficSelector meta = DefaultTrafficSelector.builder()
213 .matchVlanId(outvlan).build();
214 int portNextObjId = srManager.getPortNextObjectiveId(deviceId, outPort,
215 treatment, meta);
Saurav Das07c74602016-04-27 18:35:50 -0700216 if (portNextObjId == -1) {
217 // warning log will come from getPortNextObjective method
218 return null;
219 }
Charles Chanf4586112015-11-09 16:37:23 -0800220 return DefaultForwardingObjective.builder()
Saurav Das2d94d312015-11-24 23:21:05 -0800221 .withSelector(selector)
222 .nextStep(portNextObjId)
Charles Chanf4586112015-11-09 16:37:23 -0800223 .fromApp(srManager.appId).makePermanent()
Charles Chanddac7fd2016-10-27 14:19:48 -0700224 .withPriority(getPriorityFromPrefix(prefix))
Charles Chan82ab1932016-01-30 23:22:37 -0800225 .withFlag(ForwardingObjective.Flag.SPECIFIC);
sangho80f11cb2015-04-01 13:05:26 -0700226 }
227
228 /**
229 * Populates IP flow rules for the subnets of the destination router.
230 *
231 * @param deviceId switch ID to set the rules
Charles Chanc22cef32016-04-29 14:38:22 -0700232 * @param subnets subnet being added
sangho80f11cb2015-04-01 13:05:26 -0700233 * @param destSw destination switch ID
234 * @param nextHops next hop switch ID list
235 * @return true if all rules are set successfully, false otherwise
236 */
Pier Ventreb6a7f342016-11-26 21:05:22 -0800237 public boolean populateIpRuleForSubnet(DeviceId deviceId, Set<IpPrefix> subnets,
Charles Chanc22cef32016-04-29 14:38:22 -0700238 DeviceId destSw, Set<DeviceId> nextHops) {
Srikanth Vavilapalli64505482015-04-21 13:04:13 -0700239 for (IpPrefix subnet : subnets) {
sangho80f11cb2015-04-01 13:05:26 -0700240 if (!populateIpRuleForRouter(deviceId, subnet, destSw, nextHops)) {
241 return false;
242 }
243 }
Charles Chanc22cef32016-04-29 14:38:22 -0700244 return true;
245 }
sangho80f11cb2015-04-01 13:05:26 -0700246
Charles Chanc22cef32016-04-29 14:38:22 -0700247 /**
248 * Revokes IP flow rules for the subnets.
249 *
250 * @param subnets subnet being removed
251 * @return true if all rules are removed successfully, false otherwise
252 */
Pier Ventreb6a7f342016-11-26 21:05:22 -0800253 public boolean revokeIpRuleForSubnet(Set<IpPrefix> subnets) {
Charles Chanc22cef32016-04-29 14:38:22 -0700254 for (IpPrefix subnet : subnets) {
255 if (!revokeIpRuleForRouter(subnet)) {
256 return false;
257 }
258 }
sangho80f11cb2015-04-01 13:05:26 -0700259 return true;
260 }
261
262 /**
Saurav Dase0237a32016-05-27 13:54:07 -0700263 * Populates IP flow rules for an IP prefix in the target device. The prefix
264 * is reachable via destination device.
sangho80f11cb2015-04-01 13:05:26 -0700265 *
Saurav Das88979182015-10-19 14:37:36 -0700266 * @param deviceId target device ID to set the rules
Pier Ventreadb4ae62016-11-23 09:57:42 -0800267 * @param ipPrefix the destination IP prefix
sangho80f11cb2015-04-01 13:05:26 -0700268 * @param destSw device ID of the destination router
269 * @param nextHops next hop switch ID list
270 * @return true if all rules are set successfully, false otherwise
271 */
Srikanth Vavilapalli64505482015-04-21 13:04:13 -0700272 public boolean populateIpRuleForRouter(DeviceId deviceId,
273 IpPrefix ipPrefix, DeviceId destSw,
274 Set<DeviceId> nextHops) {
Charles Chan319d1a22015-11-03 10:42:14 -0800275 int segmentId;
276 try {
Pier Ventreadb4ae62016-11-23 09:57:42 -0800277 if (ipPrefix.isIp4()) {
278 segmentId = config.getIPv4SegmentId(destSw);
279 } else {
280 segmentId = config.getIPv6SegmentId(destSw);
281 }
Charles Chan319d1a22015-11-03 10:42:14 -0800282 } catch (DeviceConfigNotFoundException e) {
283 log.warn(e.getMessage() + " Aborting populateIpRuleForRouter.");
284 return false;
285 }
sangho80f11cb2015-04-01 13:05:26 -0700286
Pier Ventreadb4ae62016-11-23 09:57:42 -0800287 TrafficSelector.Builder sbuilder = buildIpSelectorFromIpPrefix(ipPrefix);
Charles Chanf4586112015-11-09 16:37:23 -0800288 TrafficSelector selector = sbuilder.build();
sangho80f11cb2015-04-01 13:05:26 -0700289
Charles Chanf4586112015-11-09 16:37:23 -0800290 TrafficTreatment.Builder tbuilder = DefaultTrafficTreatment.builder();
291 NeighborSet ns;
292 TrafficTreatment treatment;
sangho80f11cb2015-04-01 13:05:26 -0700293
Srikanth Vavilapalli64505482015-04-21 13:04:13 -0700294 // If the next hop is the same as the final destination, then MPLS label
295 // is not set.
sangho80f11cb2015-04-01 13:05:26 -0700296 if (nextHops.size() == 1 && nextHops.toArray()[0].equals(destSw)) {
Charles Chanf4586112015-11-09 16:37:23 -0800297 tbuilder.immediate().decNwTtl();
Pier Ventre229fd0b2016-10-31 16:49:19 -0700298 ns = new NeighborSet(nextHops, false);
Charles Chanf4586112015-11-09 16:37:23 -0800299 treatment = tbuilder.build();
sangho80f11cb2015-04-01 13:05:26 -0700300 } else {
Pier Ventre229fd0b2016-10-31 16:49:19 -0700301 ns = new NeighborSet(nextHops, false, segmentId);
Charles Chanf4586112015-11-09 16:37:23 -0800302 treatment = null;
sangho80f11cb2015-04-01 13:05:26 -0700303 }
304
Saurav Das4c35fc42015-11-20 15:27:53 -0800305 // setup metadata to pass to nextObjective - indicate the vlan on egress
306 // if needed by the switch pipeline. Since neighbor sets are always to
307 // other neighboring routers, there is no subnet assigned on those ports.
308 TrafficSelector.Builder metabuilder = DefaultTrafficSelector.builder(selector);
Charles Chan10b0fb72017-02-02 16:20:42 -0800309 metabuilder.matchVlanId(SegmentRoutingManager.INTERNAL_VLAN);
Saurav Das4c35fc42015-11-20 15:27:53 -0800310
311 int nextId = srManager.getNextObjectiveId(deviceId, ns, metabuilder.build());
312 if (nextId <= 0) {
sangho2165d222015-05-01 09:38:25 -0700313 log.warn("No next objective in {} for ns: {}", deviceId, ns);
314 return false;
315 }
316
Srikanth Vavilapalli64505482015-04-21 13:04:13 -0700317 ForwardingObjective.Builder fwdBuilder = DefaultForwardingObjective
318 .builder()
319 .fromApp(srManager.appId)
320 .makePermanent()
Saurav Das4c35fc42015-11-20 15:27:53 -0800321 .nextStep(nextId)
Srikanth Vavilapalli64505482015-04-21 13:04:13 -0700322 .withSelector(selector)
Charles Chan82ab1932016-01-30 23:22:37 -0800323 .withPriority(getPriorityFromPrefix(ipPrefix))
Srikanth Vavilapalli64505482015-04-21 13:04:13 -0700324 .withFlag(ForwardingObjective.Flag.SPECIFIC);
Charles Chanf4586112015-11-09 16:37:23 -0800325 if (treatment != null) {
326 fwdBuilder.withTreatment(treatment);
327 }
Srikanth Vavilapalli64505482015-04-21 13:04:13 -0700328 log.debug("Installing IPv4 forwarding objective "
sangho2165d222015-05-01 09:38:25 -0700329 + "for router IP/subnet {} in switch {}",
Srikanth Vavilapalli64505482015-04-21 13:04:13 -0700330 ipPrefix,
331 deviceId);
Charles Chan1eaf4802016-04-18 13:44:03 -0700332 ObjectiveContext context = new DefaultObjectiveContext(
Saurav Dase0237a32016-05-27 13:54:07 -0700333 (objective) -> log.debug("IP rule for router {} populated in dev:{}",
334 ipPrefix, deviceId),
Charles Chan1eaf4802016-04-18 13:44:03 -0700335 (objective, error) ->
Saurav Dase0237a32016-05-27 13:54:07 -0700336 log.warn("Failed to populate IP rule for router {}: {} in dev:{}",
337 ipPrefix, error, deviceId));
Charles Chan1eaf4802016-04-18 13:44:03 -0700338 srManager.flowObjectiveService.forward(deviceId, fwdBuilder.add(context));
sanghofb7c7292015-04-13 15:15:58 -0700339 rulePopulationCounter.incrementAndGet();
sangho80f11cb2015-04-01 13:05:26 -0700340
341 return true;
342 }
343
sangho80f11cb2015-04-01 13:05:26 -0700344 /**
Charles Chanc22cef32016-04-29 14:38:22 -0700345 * Revokes IP flow rules for the router IP address.
346 *
347 * @param ipPrefix the IP address of the destination router
348 * @return true if all rules are removed successfully, false otherwise
349 */
350 public boolean revokeIpRuleForRouter(IpPrefix ipPrefix) {
Pier Ventre6b2c1b32016-12-09 17:26:04 -0800351 TrafficSelector.Builder sbuilder = buildIpSelectorFromIpPrefix(ipPrefix);
Charles Chanc22cef32016-04-29 14:38:22 -0700352 TrafficSelector selector = sbuilder.build();
353 TrafficTreatment dummyTreatment = DefaultTrafficTreatment.builder().build();
354
355 ForwardingObjective.Builder fwdBuilder = DefaultForwardingObjective
356 .builder()
357 .fromApp(srManager.appId)
358 .makePermanent()
359 .withSelector(selector)
360 .withTreatment(dummyTreatment)
361 .withPriority(getPriorityFromPrefix(ipPrefix))
362 .withFlag(ForwardingObjective.Flag.SPECIFIC);
363
364 ObjectiveContext context = new DefaultObjectiveContext(
365 (objective) -> log.debug("IP rule for router {} revoked", ipPrefix),
366 (objective, error) ->
367 log.warn("Failed to revoke IP rule for router {}: {}", ipPrefix, error));
368
369 srManager.deviceService.getAvailableDevices().forEach(device -> {
370 srManager.flowObjectiveService.forward(device.id(), fwdBuilder.remove(context));
371 });
372
373 return true;
374 }
375
376 /**
Pier Ventre229fd0b2016-10-31 16:49:19 -0700377 * Deals with !MPLS Bos use case.
378 *
379 * @param targetSwId the target sw
380 * @param destSwId the destination sw
381 * @param nextHops the set of next hops
382 * @param segmentId the segmentId to match
383 * @param routerIp the router ip
384 * @return a collection of fwdobjective
385 */
386 private Collection<ForwardingObjective> handleMpls(DeviceId targetSwId,
387 DeviceId destSwId,
388 Set<DeviceId> nextHops,
389 int segmentId,
390 IpAddress routerIp,
391 boolean isMplsBos) {
392
393 TrafficSelector.Builder sbuilder = DefaultTrafficSelector.builder();
394 List<ForwardingObjective.Builder> fwdObjBuilders = Lists.newArrayList();
Pier Luigi0be3f0f2017-01-30 09:47:36 -0800395 // For the transport of Pwaas we can use two or three MPLS label
Pier Ventre229fd0b2016-10-31 16:49:19 -0700396 sbuilder.matchEthType(Ethernet.MPLS_UNICAST);
397 sbuilder.matchMplsLabel(MplsLabel.mplsLabel(segmentId));
398 sbuilder.matchMplsBos(isMplsBos);
399 TrafficSelector selector = sbuilder.build();
400
401 // setup metadata to pass to nextObjective - indicate the vlan on egress
402 // if needed by the switch pipeline. Since mpls next-hops are always to
403 // other neighboring routers, there is no subnet assigned on those ports.
404 TrafficSelector.Builder metabuilder = DefaultTrafficSelector.builder(selector);
Charles Chan10b0fb72017-02-02 16:20:42 -0800405 metabuilder.matchVlanId(SegmentRoutingManager.INTERNAL_VLAN);
Pier Ventre229fd0b2016-10-31 16:49:19 -0700406
407 if (nextHops.size() == 1 && destSwId.equals(nextHops.toArray()[0])) {
408 // If the next hop is the destination router for the segment, do pop
409 log.debug("populateMplsRule: Installing MPLS forwarding objective for "
410 + "label {} in switch {} with pop", segmentId, targetSwId);
411 // Not-bos pop case (php for the current label). If MPLS-ECMP
412 // has been configured, the application we will request the
413 // installation for an MPLS-ECMP group.
414 ForwardingObjective.Builder fwdObjNoBosBuilder = getMplsForwardingObjective(targetSwId,
415 nextHops,
416 true,
417 isMplsBos,
418 metabuilder.build(),
419 routerIp);
420 // Error case, we cannot handle, exit.
421 if (fwdObjNoBosBuilder == null) {
422 return Collections.emptyList();
423 }
424 fwdObjBuilders.add(fwdObjNoBosBuilder);
425
426 } else {
427 // next hop is not destination, SR CONTINUE case (swap with self)
428 log.debug("Installing MPLS forwarding objective for "
429 + "label {} in switch {} without pop", segmentId, targetSwId);
430 // Not-bos pop case. If MPLS-ECMP has been configured, the
431 // application we will request the installation for an MPLS-ECMP
432 // group.
433 ForwardingObjective.Builder fwdObjNoBosBuilder = getMplsForwardingObjective(targetSwId,
434 nextHops,
435 false,
436 isMplsBos,
437 metabuilder.build(),
438 routerIp);
439 // Error case, we cannot handle, exit.
440 if (fwdObjNoBosBuilder == null) {
441 return Collections.emptyList();
442 }
443 fwdObjBuilders.add(fwdObjNoBosBuilder);
444
445 }
446
447 List<ForwardingObjective> fwdObjs = Lists.newArrayList();
448 // We add the final property to the fwdObjs.
449 for (ForwardingObjective.Builder fwdObjBuilder : fwdObjBuilders) {
450
451 ((Builder) ((Builder) fwdObjBuilder
452 .fromApp(srManager.appId)
453 .makePermanent())
454 .withSelector(selector)
455 .withPriority(SegmentRoutingService.DEFAULT_PRIORITY))
456 .withFlag(ForwardingObjective.Flag.SPECIFIC);
457
458 ObjectiveContext context = new DefaultObjectiveContext(
459 (objective) ->
460 log.debug("MPLS rule {} for SID {} populated in dev:{} ",
461 objective.id(), segmentId, targetSwId),
462 (objective, error) ->
463 log.warn("Failed to populate MPLS rule {} for SID {}: {} in dev:{}",
464 objective.id(), segmentId, error, targetSwId));
465
466 ForwardingObjective fob = fwdObjBuilder.add(context);
467 fwdObjs.add(fob);
468
469 }
470
471 return fwdObjs;
472 }
473
474 /**
Saurav Dase0237a32016-05-27 13:54:07 -0700475 * Populates MPLS flow rules in the target device to point towards the
476 * destination device.
sangho80f11cb2015-04-01 13:05:26 -0700477 *
Saurav Dase0237a32016-05-27 13:54:07 -0700478 * @param targetSwId target device ID of the switch to set the rules
sangho80f11cb2015-04-01 13:05:26 -0700479 * @param destSwId destination switch device ID
480 * @param nextHops next hops switch ID list
Pier Ventre229fd0b2016-10-31 16:49:19 -0700481 * @param routerIp the router ip
sangho80f11cb2015-04-01 13:05:26 -0700482 * @return true if all rules are set successfully, false otherwise
483 */
Saurav Dase0237a32016-05-27 13:54:07 -0700484 public boolean populateMplsRule(DeviceId targetSwId, DeviceId destSwId,
Pier Ventreadb4ae62016-11-23 09:57:42 -0800485 Set<DeviceId> nextHops, IpAddress routerIp) {
Pier Ventre229fd0b2016-10-31 16:49:19 -0700486
Charles Chan319d1a22015-11-03 10:42:14 -0800487 int segmentId;
488 try {
Pier Ventreadb4ae62016-11-23 09:57:42 -0800489 if (routerIp.isIp4()) {
490 segmentId = config.getIPv4SegmentId(destSwId);
491 } else {
492 segmentId = config.getIPv6SegmentId(destSwId);
493 }
Charles Chan319d1a22015-11-03 10:42:14 -0800494 } catch (DeviceConfigNotFoundException e) {
495 log.warn(e.getMessage() + " Aborting populateMplsRule.");
496 return false;
497 }
sangho80f11cb2015-04-01 13:05:26 -0700498
Pier Ventre229fd0b2016-10-31 16:49:19 -0700499 List<ForwardingObjective> fwdObjs = new ArrayList<>();
500 Collection<ForwardingObjective> fwdObjsMpls = Collections.emptyList();
501 // Generates the transit rules used by the standard "routing".
502 fwdObjsMpls = handleMpls(targetSwId, destSwId, nextHops, segmentId, routerIp, true);
503 if (fwdObjsMpls.isEmpty()) {
504 return false;
sangho80f11cb2015-04-01 13:05:26 -0700505 }
Pier Ventre229fd0b2016-10-31 16:49:19 -0700506 fwdObjs.addAll(fwdObjsMpls);
Pier Luigi0be3f0f2017-01-30 09:47:36 -0800507 // Generates the transit rules used by the MPLS Pwaas. For now it is
Pier Ventre229fd0b2016-10-31 16:49:19 -0700508 // the only case !BoS supported.
Saurav Dasf9332192017-02-18 14:05:44 -0800509 /*fwdObjsMpls = handleMpls(targetSwId, destSwId, nextHops, segmentId, routerIp, false);
Pier Ventre229fd0b2016-10-31 16:49:19 -0700510 if (fwdObjsMpls.isEmpty()) {
511 return false;
512 }
Saurav Dasf9332192017-02-18 14:05:44 -0800513 fwdObjs.addAll(fwdObjsMpls);*/
Pier Ventre229fd0b2016-10-31 16:49:19 -0700514
515 for (ForwardingObjective fwdObj : fwdObjs) {
Saurav Dase0237a32016-05-27 13:54:07 -0700516 log.debug("Sending MPLS fwd obj {} for SID {}-> next {} in sw: {}",
Pier Ventre229fd0b2016-10-31 16:49:19 -0700517 fwdObj.id(), segmentId, fwdObj.nextId(), targetSwId);
518 srManager.flowObjectiveService.forward(targetSwId, fwdObj);
sanghofb7c7292015-04-13 15:15:58 -0700519 rulePopulationCounter.incrementAndGet();
sangho80f11cb2015-04-01 13:05:26 -0700520 }
521
522 return true;
523 }
524
Saurav Das4c35fc42015-11-20 15:27:53 -0800525 private ForwardingObjective.Builder getMplsForwardingObjective(
526 DeviceId deviceId,
527 Set<DeviceId> nextHops,
528 boolean phpRequired,
529 boolean isBos,
Pier Ventreadb4ae62016-11-23 09:57:42 -0800530 TrafficSelector meta,
531 IpAddress routerIp) {
Saurav Das4c35fc42015-11-20 15:27:53 -0800532
Srikanth Vavilapalli64505482015-04-21 13:04:13 -0700533 ForwardingObjective.Builder fwdBuilder = DefaultForwardingObjective
534 .builder().withFlag(ForwardingObjective.Flag.SPECIFIC);
sangho80f11cb2015-04-01 13:05:26 -0700535
536 TrafficTreatment.Builder tbuilder = DefaultTrafficTreatment.builder();
537
538 if (phpRequired) {
Saurav Das4c35fc42015-11-20 15:27:53 -0800539 // php case - pop should always be flow-action
Srikanth Vavilapalli64505482015-04-21 13:04:13 -0700540 log.debug("getMplsForwardingObjective: php required");
sangho27462c62015-05-14 00:39:53 -0700541 tbuilder.deferred().copyTtlIn();
sangho80f11cb2015-04-01 13:05:26 -0700542 if (isBos) {
Pier Ventreadb4ae62016-11-23 09:57:42 -0800543 if (routerIp.isIp4()) {
544 tbuilder.deferred().popMpls(EthType.EtherType.IPV4.ethType());
545 } else {
546 tbuilder.deferred().popMpls(EthType.EtherType.IPV6.ethType());
547 }
548 tbuilder.decNwTtl();
sangho80f11cb2015-04-01 13:05:26 -0700549 } else {
Saurav Das4c35fc42015-11-20 15:27:53 -0800550 tbuilder.deferred().popMpls(EthType.EtherType.MPLS_UNICAST.ethType())
551 .decMplsTtl();
sangho80f11cb2015-04-01 13:05:26 -0700552 }
553 } else {
Saurav Das4c35fc42015-11-20 15:27:53 -0800554 // swap with self case - SR CONTINUE
Srikanth Vavilapalli64505482015-04-21 13:04:13 -0700555 log.debug("getMplsForwardingObjective: php not required");
sangho27462c62015-05-14 00:39:53 -0700556 tbuilder.deferred().decMplsTtl();
sangho80f11cb2015-04-01 13:05:26 -0700557 }
558
Saurav Das4c35fc42015-11-20 15:27:53 -0800559 fwdBuilder.withTreatment(tbuilder.build());
Pier Ventre229fd0b2016-10-31 16:49:19 -0700560 // if MPLS-ECMP == True we will build a standard NeighborSet.
561 // Otherwise a RandomNeighborSet.
562 NeighborSet ns = NeighborSet.neighborSet(false, nextHops, false);
563 if (!isBos && this.srManager.getMplsEcmp()) {
564 ns = NeighborSet.neighborSet(false, nextHops, true);
565 } else if (!isBos && !this.srManager.getMplsEcmp()) {
566 ns = NeighborSet.neighborSet(true, nextHops, true);
567 }
568 log.info("Trying to get a nextObjId for mpls rule on device:{} to ns:{}",
569 deviceId, ns);
570 // If BoS == True, all forwarding is via L3 ECMP group.
571 // If Bos == False, the forwarding can be via MPLS-ECMP group or through
572 // MPLS-Interface group. This depends on the configuration of the option
573 // MPLS-ECMP.
574 // The metadata informs the driver that the next-Objective will be used
575 // by MPLS flows and if Bos == False the driver will use MPLS groups.
576 int nextId = srManager.getNextObjectiveId(deviceId, ns, meta, isBos);
Saurav Das4c35fc42015-11-20 15:27:53 -0800577 if (nextId <= 0) {
578 log.warn("No next objective in {} for ns: {}", deviceId, ns);
579 return null;
Saurav Dase0237a32016-05-27 13:54:07 -0700580 } else {
581 log.debug("nextObjId found:{} for mpls rule on device:{} to ns:{}",
582 nextId, deviceId, ns);
sangho80f11cb2015-04-01 13:05:26 -0700583 }
584
Saurav Das4c35fc42015-11-20 15:27:53 -0800585 fwdBuilder.nextStep(nextId);
Srikanth Vavilapalli64505482015-04-21 13:04:13 -0700586 return fwdBuilder;
sangho80f11cb2015-04-01 13:05:26 -0700587 }
588
589 /**
Saurav Das9f1c42e2015-10-23 10:51:11 -0700590 * Creates a filtering objective to permit all untagged packets with a
Saurav Das7c305372015-10-28 12:39:42 -0700591 * dstMac corresponding to the router's MAC address. For those pipelines
592 * that need to internally assign vlans to untagged packets, this method
593 * provides per-subnet vlan-ids as metadata.
Saurav Dasc28b3432015-10-30 17:45:38 -0700594 * <p>
Saurav Dasf9332192017-02-18 14:05:44 -0800595 * Note that the vlan assignment and filter programming should only be done by
596 * the master for a switch. This method is typically called at deviceAdd and
597 * programs filters only for the enabled ports of the device. For port-updates,
598 * that enable/disable ports after device add, singlePortFilter methods should
599 * be called.
sangho80f11cb2015-04-01 13:05:26 -0700600 *
Saurav Das9f1c42e2015-10-23 10:51:11 -0700601 * @param deviceId the switch dpid for the router
Saurav Dasd1872b02016-12-02 15:43:47 -0800602 * @return PortFilterInfo information about the processed ports
sangho80f11cb2015-04-01 13:05:26 -0700603 */
Charles Chan18fa4252017-02-08 16:10:40 -0800604 public PortFilterInfo populateVlanMacFilters(DeviceId deviceId) {
Saurav Das7c305372015-10-28 12:39:42 -0700605 log.debug("Installing per-port filtering objective for untagged "
606 + "packets in device {}", deviceId);
Charles Chan319d1a22015-11-03 10:42:14 -0800607
Saurav Das07c74602016-04-27 18:35:50 -0700608 List<Port> devPorts = srManager.deviceService.getPorts(deviceId);
Jon Hall31d84782017-01-18 20:15:44 -0800609 if (devPorts == null || devPorts.isEmpty()) {
Saurav Das07c74602016-04-27 18:35:50 -0700610 log.warn("Device {} ports not available. Unable to add MacVlan filters",
611 deviceId);
Saurav Dasd1872b02016-12-02 15:43:47 -0800612 return null;
Saurav Das07c74602016-04-27 18:35:50 -0700613 }
Saurav Dasf9332192017-02-18 14:05:44 -0800614 int disabledPorts = 0, errorPorts = 0, filteredPorts = 0;
Saurav Das07c74602016-04-27 18:35:50 -0700615 for (Port port : devPorts) {
Saurav Dase0237a32016-05-27 13:54:07 -0700616 if (!port.isEnabled()) {
617 disabledPorts++;
618 continue;
619 }
Saurav Dasf9332192017-02-18 14:05:44 -0800620 if (populateSinglePortFilters(deviceId, port.number())) {
621 filteredPorts++;
622 } else {
623 errorPorts++;
Saurav Dase0237a32016-05-27 13:54:07 -0700624 }
Saurav Das7c305372015-10-28 12:39:42 -0700625 }
Saurav Dasf9332192017-02-18 14:05:44 -0800626 log.info("Filtering on dev:{}, disabledPorts:{}, errorPorts:{}, filteredPorts:{}",
627 deviceId, disabledPorts, errorPorts, filteredPorts);
Saurav Dasd1872b02016-12-02 15:43:47 -0800628 return srManager.defaultRoutingHandler.new PortFilterInfo(disabledPorts,
Saurav Dasf9332192017-02-18 14:05:44 -0800629 errorPorts, filteredPorts);
630 }
631
632 /**
633 * Creates filtering objectives for a single port. Should only be called
634 * by the master for a switch.
635 *
636 * @param deviceId device identifier
637 * @param portnum port identifier for port to be filtered
638 * @return true if no errors occurred during the build of the filtering objective
639 */
640 public boolean populateSinglePortFilters(DeviceId deviceId, PortNumber portnum) {
641 FilteringObjective.Builder fob = buildFilteringObjective(deviceId, portnum);
642 if (fob == null) {
643 // error encountered during build
644 return false;
645 }
646 log.info("Sending filtering objectives for dev/port:{}/{}", deviceId, portnum);
647 ObjectiveContext context = new DefaultObjectiveContext(
648 (objective) -> log.debug("Filter for {}/{} populated", deviceId, portnum),
649 (objective, error) ->
650 log.warn("Failed to populate filter for {}/{}: {}",
651 deviceId, portnum, error));
652 srManager.flowObjectiveService.filter(deviceId, fob.add(context));
653 return true;
654 }
655
656 /**
657 * Removes filtering objectives for a single port. Should only be called
658 * by the master for a switch.
659 *
660 * @param deviceId device identifier
661 * @param portnum port identifier
662 */
663 public void revokeSinglePortFilters(DeviceId deviceId, PortNumber portnum) {
664 FilteringObjective.Builder fob = buildFilteringObjective(deviceId, portnum);
665 if (fob == null) {
666 // error encountered during build
667 return;
668 }
669 log.info("Removing filtering objectives for dev/port:{}/{}", deviceId, portnum);
670 ObjectiveContext context = new DefaultObjectiveContext(
671 (objective) -> log.debug("Filter for {}/{} removed", deviceId, portnum),
672 (objective, error) ->
673 log.warn("Failed to remove filter for {}/{}: {}",
674 deviceId, portnum, error));
675 srManager.flowObjectiveService.filter(deviceId, fob.remove(context));
676 return;
677 }
678
Saurav Dasf9332192017-02-18 14:05:44 -0800679 private FilteringObjective.Builder buildFilteringObjective(DeviceId deviceId,
680 PortNumber portnum) {
681 MacAddress deviceMac;
682 try {
683 deviceMac = config.getDeviceMac(deviceId);
684 } catch (DeviceConfigNotFoundException e) {
685 log.warn(e.getMessage() + " Processing SinglePortFilters aborted");
686 return null;
687 }
688 // suppressed ports still have filtering rules pushed by SR using default vlan
689 ConnectPoint connectPoint = new ConnectPoint(deviceId, portnum);
Saurav Dasf9332192017-02-18 14:05:44 -0800690
Charles Chan10b0fb72017-02-02 16:20:42 -0800691 VlanId untaggedVlan = srManager.getUntaggedVlanId(connectPoint);
692 VlanId assignedVlan = (untaggedVlan != null) ? untaggedVlan : INTERNAL_VLAN;
Saurav Dasf9332192017-02-18 14:05:44 -0800693
694 FilteringObjective.Builder fob = DefaultFilteringObjective.builder();
695 fob.withKey(Criteria.matchInPort(portnum))
696 .addCondition(Criteria.matchEthDst(deviceMac))
697 .addCondition(Criteria.matchVlanId(VlanId.NONE))
698 .withPriority(SegmentRoutingService.DEFAULT_PRIORITY);
699 TrafficTreatment tt = DefaultTrafficTreatment.builder()
700 .pushVlan().setVlanId(assignedVlan).build();
701 fob.withMeta(tt);
702 fob.permit().fromApp(srManager.appId);
703 return fob;
sangho80f11cb2015-04-01 13:05:26 -0700704 }
705
706 /**
Saurav Das9f1c42e2015-10-23 10:51:11 -0700707 * Creates a forwarding objective to punt all IP packets, destined to the
Saurav Dasc28b3432015-10-30 17:45:38 -0700708 * router's port IP addresses, to the controller. Note that the input
Saurav Das9f1c42e2015-10-23 10:51:11 -0700709 * port should not be matched on, as these packets can come from any input.
Saurav Dasc28b3432015-10-30 17:45:38 -0700710 * Furthermore, these are applied only by the master instance.
sangho80f11cb2015-04-01 13:05:26 -0700711 *
Saurav Das9f1c42e2015-10-23 10:51:11 -0700712 * @param deviceId the switch dpid for the router
sangho80f11cb2015-04-01 13:05:26 -0700713 */
Charles Chan18fa4252017-02-08 16:10:40 -0800714 public void populateIpPunts(DeviceId deviceId) {
Pier Ventreadb4ae62016-11-23 09:57:42 -0800715 Ip4Address routerIpv4;
716 Ip6Address routerIpv6;
Charles Chan319d1a22015-11-03 10:42:14 -0800717 try {
Pier Ventreadb4ae62016-11-23 09:57:42 -0800718 routerIpv4 = config.getRouterIpv4(deviceId);
719 routerIpv6 = config.getRouterIpv6(deviceId);
Charles Chan319d1a22015-11-03 10:42:14 -0800720 } catch (DeviceConfigNotFoundException e) {
Charles Chan18fa4252017-02-08 16:10:40 -0800721 log.warn(e.getMessage() + " Aborting populateIpPunts.");
Charles Chan319d1a22015-11-03 10:42:14 -0800722 return;
723 }
724
Saurav Dasc28b3432015-10-30 17:45:38 -0700725 if (!srManager.mastershipService.isLocalMaster(deviceId)) {
726 log.debug("Not installing port-IP punts - not the master for dev:{} ",
727 deviceId);
728 return;
729 }
Pier Ventreadb4ae62016-11-23 09:57:42 -0800730 Set<IpAddress> allIps = new HashSet<>(config.getPortIPs(deviceId));
731 allIps.add(routerIpv4);
732 if (routerIpv6 != null) {
733 allIps.add(routerIpv6);
734 }
735 for (IpAddress ipaddr : allIps) {
736 TrafficSelector.Builder sbuilder = buildIpSelectorFromIpAddress(ipaddr);
Charles Chan2d0bbcd2017-01-09 11:45:08 -0800737 Optional<DeviceId> optDeviceId = Optional.of(deviceId);
738
739 srManager.packetService.requestPackets(sbuilder.build(),
740 PacketPriority.CONTROL, srManager.appId, optDeviceId);
Saurav Das9f1c42e2015-10-23 10:51:11 -0700741 }
sangho80f11cb2015-04-01 13:05:26 -0700742 }
743
Charles Chanf4586112015-11-09 16:37:23 -0800744 /**
Pier Ventreadb4ae62016-11-23 09:57:42 -0800745 * Method to build IPv4 or IPv6 selector.
746 *
747 * @param addressToMatch the address to match
748 */
749 private TrafficSelector.Builder buildIpSelectorFromIpAddress(IpAddress addressToMatch) {
750 return buildIpSelectorFromIpPrefix(addressToMatch.toIpPrefix());
751 }
752
753 /**
754 * Method to build IPv4 or IPv6 selector.
755 *
756 * @param prefixToMatch the prefix to match
757 */
758 private TrafficSelector.Builder buildIpSelectorFromIpPrefix(IpPrefix prefixToMatch) {
759 TrafficSelector.Builder selectorBuilder = DefaultTrafficSelector.builder();
Pier Ventre229fd0b2016-10-31 16:49:19 -0700760 // If the prefix is IPv4
Pier Ventreadb4ae62016-11-23 09:57:42 -0800761 if (prefixToMatch.isIp4()) {
762 selectorBuilder.matchEthType(Ethernet.TYPE_IPV4);
763 selectorBuilder.matchIPDst(prefixToMatch.getIp4Prefix());
764 return selectorBuilder;
765 }
Pier Ventre229fd0b2016-10-31 16:49:19 -0700766 // If the prefix is IPv6
Pier Ventreadb4ae62016-11-23 09:57:42 -0800767 selectorBuilder.matchEthType(Ethernet.TYPE_IPV6);
768 selectorBuilder.matchIPv6Dst(prefixToMatch.getIp6Prefix());
769 return selectorBuilder;
770 }
771
772 /**
Pier Luigib9632ba2017-01-12 18:14:58 -0800773 * Creates forwarding objectives to punt ARP and NDP packets, to the controller.
774 * Furthermore, these are applied only by the master instance. Deferred actions
775 * are not cleared such that packets can be flooded in the cross connect use case
776 *
777 * @param deviceId the switch dpid for the router
778 */
779 public void populateArpNdpPunts(DeviceId deviceId) {
Pier Ventre229fd0b2016-10-31 16:49:19 -0700780 // We are not the master just skip.
Pier Luigib9632ba2017-01-12 18:14:58 -0800781 if (!srManager.mastershipService.isLocalMaster(deviceId)) {
782 log.debug("Not installing ARP/NDP punts - not the master for dev:{} ",
783 deviceId);
784 return;
785 }
786
787 // We punt all ARP packets towards the controller.
788 ForwardingObjective puntFwd = puntArpFwdObjective()
789 .add(new ObjectiveContext() {
790 @Override
791 public void onError(Objective objective, ObjectiveError error) {
792 log.warn("Failed to install packet request for ARP to {}: {}",
793 deviceId, error);
794 }
795 });
796 srManager.flowObjectiveService.forward(deviceId, puntFwd);
797
Pier Luigib9632ba2017-01-12 18:14:58 -0800798 // We punt all NDP packets towards the controller.
Pier Luigib9632ba2017-01-12 18:14:58 -0800799 puntFwd = puntNdpFwdObjective()
800 .add(new ObjectiveContext() {
801 @Override
802 public void onError(Objective objective, ObjectiveError error) {
803 log.warn("Failed to install packet request for NDP to {}: {}",
804 deviceId, error);
805 }
806 });
807 srManager.flowObjectiveService.forward(deviceId, puntFwd);
Pier Luigib9632ba2017-01-12 18:14:58 -0800808 }
809
810 private ForwardingObjective.Builder fwdObjBuilder(TrafficSelector selector) {
811
812 TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder();
813 tBuilder.punt();
814
815 return DefaultForwardingObjective.builder()
816 .withPriority(PacketPriority.CONTROL.priorityValue())
817 .withSelector(selector)
818 .fromApp(srManager.appId)
819 .withFlag(ForwardingObjective.Flag.VERSATILE)
820 .withTreatment(tBuilder.build())
821 .makePermanent();
822 }
823
824 private ForwardingObjective.Builder puntArpFwdObjective() {
825
826 TrafficSelector.Builder sBuilder = DefaultTrafficSelector.builder();
827 sBuilder.matchEthType(TYPE_ARP);
828
829 return fwdObjBuilder(sBuilder.build());
830 }
831
832 private ForwardingObjective.Builder puntNdpFwdObjective() {
833
834 TrafficSelector.Builder sBuilder = DefaultTrafficSelector.builder();
835 sBuilder.matchEthType(TYPE_IPV6)
836 .matchIPProtocol(PROTOCOL_ICMP6)
837 .matchIcmpv6Type(NEIGHBOR_SOLICITATION)
838 .build();
839
840 return fwdObjBuilder(sBuilder.build());
841 }
842
843 /**
Charles Chanf4586112015-11-09 16:37:23 -0800844 * Populates a forwarding objective to send packets that miss other high
845 * priority Bridging Table entries to a group that contains all ports of
846 * its subnet.
847 *
848 * Note: We assume that packets sending from the edge switches to the hosts
849 * have untagged VLAN.
850 * The VLAN tag will be popped later in the flooding group.
851 *
852 * @param deviceId switch ID to set the rules
853 */
854 public void populateSubnetBroadcastRule(DeviceId deviceId) {
Charles Chan10b0fb72017-02-02 16:20:42 -0800855 Set<Interface> interfaces = srManager.interfaceService.getInterfaces();
856 Set<VlanId> vlans =
857 interfaces.stream()
858 .filter(intf -> intf.connectPoint().deviceId().equals(deviceId) &&
859 !intf.vlanUntagged().equals(VlanId.NONE))
860 .map(Interface::vlanUntagged)
861 .collect(Collectors.toSet());
Charles Chanf4586112015-11-09 16:37:23 -0800862
Charles Chan10b0fb72017-02-02 16:20:42 -0800863 vlans.forEach(vlanId -> {
864 int nextId = srManager.getVlanNextObjectiveId(deviceId, vlanId);
865
866 if (nextId < 0) {
867 log.error("Cannot install vlan {} broadcast rule in dev:{} due"
868 + "to vlanId:{} or nextId:{}", vlanId, deviceId, vlanId, nextId);
Saurav Das2d94d312015-11-24 23:21:05 -0800869 return;
870 }
871
Pier Ventre229fd0b2016-10-31 16:49:19 -0700872 // Driver should treat objective with MacAddress.NONE as the
873 // subnet broadcast rule
Charles Chanf4586112015-11-09 16:37:23 -0800874 TrafficSelector.Builder sbuilder = DefaultTrafficSelector.builder();
875 sbuilder.matchVlanId(vlanId);
876 sbuilder.matchEthDst(MacAddress.NONE);
877
878 ForwardingObjective.Builder fob = DefaultForwardingObjective.builder();
879 fob.withFlag(Flag.SPECIFIC)
880 .withSelector(sbuilder.build())
881 .nextStep(nextId)
Charles Chan82ab1932016-01-30 23:22:37 -0800882 .withPriority(SegmentRoutingService.FLOOD_PRIORITY)
Charles Chanf4586112015-11-09 16:37:23 -0800883 .fromApp(srManager.appId)
884 .makePermanent();
Charles Chan1eaf4802016-04-18 13:44:03 -0700885 ObjectiveContext context = new DefaultObjectiveContext(
Charles Chan10b0fb72017-02-02 16:20:42 -0800886 (objective) -> log.debug("Vlan broadcast rule for {} populated", vlanId),
Charles Chan1eaf4802016-04-18 13:44:03 -0700887 (objective, error) ->
Charles Chan10b0fb72017-02-02 16:20:42 -0800888 log.warn("Failed to populate vlan broadcast rule for {}: {}", vlanId, error));
Charles Chan1eaf4802016-04-18 13:44:03 -0700889 srManager.flowObjectiveService.forward(deviceId, fob.add(context));
Charles Chanf4586112015-11-09 16:37:23 -0800890 });
891 }
892
Charles Chan82ab1932016-01-30 23:22:37 -0800893 private int getPriorityFromPrefix(IpPrefix prefix) {
894 return (prefix.isIp4()) ?
895 2000 * prefix.prefixLength() + SegmentRoutingService.MIN_IP_PRIORITY :
896 500 * prefix.prefixLength() + SegmentRoutingService.MIN_IP_PRIORITY;
Srikanth Vavilapalli8c83f1d2015-05-22 13:47:31 -0700897 }
sangho80f11cb2015-04-01 13:05:26 -0700898}