blob: 2c2f1eb373212091ff27c7a7ba86f815c64c6644 [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
Saurav Das4c35fc42015-11-20 15:27:53 -080018import org.onlab.packet.EthType;
sangho80f11cb2015-04-01 13:05:26 -070019import org.onlab.packet.Ethernet;
20import org.onlab.packet.Ip4Address;
Srikanth Vavilapalli37a461b2015-04-07 15:12:32 -070021import org.onlab.packet.Ip4Prefix;
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 Chanb7f75ac2016-01-11 18:28:54 -080028import org.onosproject.net.ConnectPoint;
Charles Chan1eaf4802016-04-18 13:44:03 -070029import org.onosproject.net.flowobjective.DefaultObjectiveContext;
Pier Luigib9632ba2017-01-12 18:14:58 -080030import org.onosproject.net.flowobjective.Objective;
Charles Chan1eaf4802016-04-18 13:44:03 -070031import org.onosproject.net.flowobjective.ObjectiveContext;
Pier Luigib9632ba2017-01-12 18:14:58 -080032import org.onosproject.net.flowobjective.ObjectiveError;
Charles Chan2d0bbcd2017-01-09 11:45:08 -080033import org.onosproject.net.packet.PacketPriority;
Saurav Dasd1872b02016-12-02 15:43:47 -080034import org.onosproject.segmentrouting.DefaultRoutingHandler.PortFilterInfo;
Charles Chan319d1a22015-11-03 10:42:14 -080035import org.onosproject.segmentrouting.config.DeviceConfigNotFoundException;
36import org.onosproject.segmentrouting.config.DeviceConfiguration;
Charles Chan370a65b2016-05-10 17:29:47 -070037import org.onosproject.segmentrouting.config.SegmentRoutingAppConfig;
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;
Saurav Dasc28b3432015-10-30 17:45:38 -070057import java.util.HashSet;
sangho80f11cb2015-04-01 13:05:26 -070058import java.util.List;
Charles Chan2d0bbcd2017-01-09 11:45:08 -080059import java.util.Optional;
sangho80f11cb2015-04-01 13:05:26 -070060import java.util.Set;
sanghofb7c7292015-04-13 15:15:58 -070061import java.util.concurrent.atomic.AtomicLong;
sangho80f11cb2015-04-01 13:05:26 -070062
63import static com.google.common.base.Preconditions.checkNotNull;
Pier Luigib9632ba2017-01-12 18:14:58 -080064import static org.onlab.packet.Ethernet.TYPE_ARP;
65import static org.onlab.packet.Ethernet.TYPE_IPV6;
66import static org.onlab.packet.ICMP6.NEIGHBOR_SOLICITATION;
67import static org.onlab.packet.IPv6.PROTOCOL_ICMP6;
sangho80f11cb2015-04-01 13:05:26 -070068
Charles Chanb7f75ac2016-01-11 18:28:54 -080069/**
70 * Populator of segment routing flow rules.
71 */
sangho80f11cb2015-04-01 13:05:26 -070072public class RoutingRulePopulator {
Srikanth Vavilapalli64505482015-04-21 13:04:13 -070073 private static final Logger log = LoggerFactory
74 .getLogger(RoutingRulePopulator.class);
sangho80f11cb2015-04-01 13:05:26 -070075
sanghofb7c7292015-04-13 15:15:58 -070076 private AtomicLong rulePopulationCounter;
sangho9b169e32015-04-14 16:27:13 -070077 private SegmentRoutingManager srManager;
78 private DeviceConfiguration config;
Saurav Das9f1c42e2015-10-23 10:51:11 -070079
sangho80f11cb2015-04-01 13:05:26 -070080 /**
81 * Creates a RoutingRulePopulator object.
82 *
Thomas Vachuska8a075092015-04-15 18:20:08 -070083 * @param srManager segment routing manager reference
sangho80f11cb2015-04-01 13:05:26 -070084 */
85 public RoutingRulePopulator(SegmentRoutingManager srManager) {
86 this.srManager = srManager;
sangho9b169e32015-04-14 16:27:13 -070087 this.config = checkNotNull(srManager.deviceConfiguration);
sanghofb7c7292015-04-13 15:15:58 -070088 this.rulePopulationCounter = new AtomicLong(0);
89 }
90
91 /**
92 * Resets the population counter.
93 */
94 public void resetCounter() {
95 rulePopulationCounter.set(0);
96 }
97
98 /**
99 * Returns the number of rules populated.
Thomas Vachuska7cfc6202015-04-30 18:13:25 -0700100 *
101 * @return number of rules
sanghofb7c7292015-04-13 15:15:58 -0700102 */
103 public long getCounter() {
104 return rulePopulationCounter.get();
sangho80f11cb2015-04-01 13:05:26 -0700105 }
106
107 /**
Charles Chanddac7fd2016-10-27 14:19:48 -0700108 * Populates IP rules for a route that has direct connection to the
Srikanth Vavilapalli64505482015-04-21 13:04:13 -0700109 * switch.
sangho80f11cb2015-04-01 13:05:26 -0700110 *
Charles Chanddac7fd2016-10-27 14:19:48 -0700111 * @param deviceId device ID of the device that next hop attaches to
112 * @param prefix IP prefix of the route
113 * @param hostMac MAC address of the next hop
114 * @param outPort port where the next hop attaches to
sangho80f11cb2015-04-01 13:05:26 -0700115 */
Charles Chanddac7fd2016-10-27 14:19:48 -0700116 public void populateRoute(DeviceId deviceId, IpPrefix prefix,
sangho80f11cb2015-04-01 13:05:26 -0700117 MacAddress hostMac, PortNumber outPort) {
Charles Chanddac7fd2016-10-27 14:19:48 -0700118 log.debug("Populate IP table entry for route {} at {}:{}",
119 prefix, deviceId, outPort);
Charles Chanf4586112015-11-09 16:37:23 -0800120 ForwardingObjective.Builder fwdBuilder;
Charles Chan319d1a22015-11-03 10:42:14 -0800121 try {
Charles Chanf4586112015-11-09 16:37:23 -0800122 fwdBuilder = getForwardingObjectiveBuilder(
Charles Chanddac7fd2016-10-27 14:19:48 -0700123 deviceId, prefix, hostMac, outPort);
Charles Chan319d1a22015-11-03 10:42:14 -0800124 } catch (DeviceConfigNotFoundException e) {
125 log.warn(e.getMessage() + " Aborting populateIpRuleForHost.");
126 return;
127 }
Saurav Das07c74602016-04-27 18:35:50 -0700128 if (fwdBuilder == null) {
129 log.warn("Aborting host routing table entries due "
Charles Chanddac7fd2016-10-27 14:19:48 -0700130 + "to error for dev:{} route:{}", deviceId, prefix);
Saurav Das07c74602016-04-27 18:35:50 -0700131 return;
132 }
Charles Chan1eaf4802016-04-18 13:44:03 -0700133 ObjectiveContext context = new DefaultObjectiveContext(
Charles Chanddac7fd2016-10-27 14:19:48 -0700134 (objective) -> log.debug("IP rule for route {} populated", prefix),
Charles Chan1eaf4802016-04-18 13:44:03 -0700135 (objective, error) ->
Charles Chanddac7fd2016-10-27 14:19:48 -0700136 log.warn("Failed to populate IP rule for route {}: {}", prefix, error));
Charles Chan1eaf4802016-04-18 13:44:03 -0700137 srManager.flowObjectiveService.forward(deviceId, fwdBuilder.add(context));
Charles Chanf4586112015-11-09 16:37:23 -0800138 rulePopulationCounter.incrementAndGet();
139 }
140
Charles Chanb7f75ac2016-01-11 18:28:54 -0800141 /**
Charles Chanddac7fd2016-10-27 14:19:48 -0700142 * Removes IP rules for a route when the next hop is gone.
Charles Chanb7f75ac2016-01-11 18:28:54 -0800143 *
Charles Chanddac7fd2016-10-27 14:19:48 -0700144 * @param deviceId device ID of the device that next hop attaches to
145 * @param prefix IP prefix of the route
146 * @param hostMac MAC address of the next hop
147 * @param outPort port that next hop attaches to
Charles Chanb7f75ac2016-01-11 18:28:54 -0800148 */
Charles Chanddac7fd2016-10-27 14:19:48 -0700149 public void revokeRoute(DeviceId deviceId, IpPrefix prefix,
Charles Chanf4586112015-11-09 16:37:23 -0800150 MacAddress hostMac, PortNumber outPort) {
Charles Chanddac7fd2016-10-27 14:19:48 -0700151 log.debug("Revoke IP table entry for route {} at {}:{}",
152 prefix, deviceId, outPort);
Charles Chanf4586112015-11-09 16:37:23 -0800153 ForwardingObjective.Builder fwdBuilder;
154 try {
155 fwdBuilder = getForwardingObjectiveBuilder(
Charles Chanddac7fd2016-10-27 14:19:48 -0700156 deviceId, prefix, hostMac, outPort);
Charles Chanf4586112015-11-09 16:37:23 -0800157 } catch (DeviceConfigNotFoundException e) {
158 log.warn(e.getMessage() + " Aborting revokeIpRuleForHost.");
159 return;
160 }
Charles Chanea702b12016-11-30 11:55:05 -0800161 if (fwdBuilder == null) {
162 log.warn("Aborting host routing table entries due "
163 + "to error for dev:{} route:{}", deviceId, prefix);
164 return;
165 }
Charles Chan1eaf4802016-04-18 13:44:03 -0700166 ObjectiveContext context = new DefaultObjectiveContext(
Charles Chanddac7fd2016-10-27 14:19:48 -0700167 (objective) -> log.debug("IP rule for route {} revoked", prefix),
Charles Chan1eaf4802016-04-18 13:44:03 -0700168 (objective, error) ->
Charles Chanddac7fd2016-10-27 14:19:48 -0700169 log.warn("Failed to revoke IP rule for route {}: {}", prefix, error));
Charles Chan1eaf4802016-04-18 13:44:03 -0700170 srManager.flowObjectiveService.forward(deviceId, fwdBuilder.remove(context));
Charles Chanf4586112015-11-09 16:37:23 -0800171 }
172
Charles Chanddac7fd2016-10-27 14:19:48 -0700173 /**
174 * Returns a forwarding objective that points packets destined to a
175 * given prefix to given port on given device with given destination MAC.
176 *
177 * @param deviceId device ID
178 * @param prefix prefix that need to be routed
179 * @param hostMac MAC address of the nexthop
180 * @param outPort port where the nexthop attaches to
181 * @return forwarding objective builder
182 * @throws DeviceConfigNotFoundException if given device is not configured
183 */
Charles Chanf4586112015-11-09 16:37:23 -0800184 private ForwardingObjective.Builder getForwardingObjectiveBuilder(
Charles Chanddac7fd2016-10-27 14:19:48 -0700185 DeviceId deviceId, IpPrefix prefix,
Charles Chanf4586112015-11-09 16:37:23 -0800186 MacAddress hostMac, PortNumber outPort)
187 throws DeviceConfigNotFoundException {
188 MacAddress deviceMac;
189 deviceMac = config.getDeviceMac(deviceId);
Charles Chan319d1a22015-11-03 10:42:14 -0800190
sangho80f11cb2015-04-01 13:05:26 -0700191 TrafficSelector.Builder sbuilder = DefaultTrafficSelector.builder();
sangho80f11cb2015-04-01 13:05:26 -0700192 sbuilder.matchEthType(Ethernet.TYPE_IPV4);
Charles Chanddac7fd2016-10-27 14:19:48 -0700193 sbuilder.matchIPDst(prefix);
Saurav Das2d94d312015-11-24 23:21:05 -0800194 TrafficSelector selector = sbuilder.build();
sangho80f11cb2015-04-01 13:05:26 -0700195
Charles Chanddac7fd2016-10-27 14:19:48 -0700196 TrafficTreatment.Builder tbuilder = DefaultTrafficTreatment.builder();
sangho27462c62015-05-14 00:39:53 -0700197 tbuilder.deferred()
198 .setEthDst(hostMac)
Charles Chan319d1a22015-11-03 10:42:14 -0800199 .setEthSrc(deviceMac)
sangho80f11cb2015-04-01 13:05:26 -0700200 .setOutput(outPort);
sangho80f11cb2015-04-01 13:05:26 -0700201 TrafficTreatment treatment = tbuilder.build();
Saurav Das2d94d312015-11-24 23:21:05 -0800202
203 // All forwarding is via Groups. Drivers can re-purpose to flow-actions if needed.
204 // for switch pipelines that need it, provide outgoing vlan as metadata
205 VlanId outvlan = null;
206 Ip4Prefix subnet = srManager.deviceConfiguration.getPortSubnet(deviceId, outPort);
207 if (subnet == null) {
208 outvlan = VlanId.vlanId(SegmentRoutingManager.ASSIGNED_VLAN_NO_SUBNET);
209 } else {
210 outvlan = srManager.getSubnetAssignedVlanId(deviceId, subnet);
211 }
212 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 */
Charles Chanc22cef32016-04-29 14:38:22 -0700237 public boolean populateIpRuleForSubnet(DeviceId deviceId, Set<Ip4Prefix> subnets,
238 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 */
253 public boolean revokeIpRuleForSubnet(Set<Ip4Prefix> subnets) {
254 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();
sangho80f11cb2015-04-01 13:05:26 -0700298 ns = new NeighborSet(nextHops);
Charles Chanf4586112015-11-09 16:37:23 -0800299 treatment = tbuilder.build();
sangho80f11cb2015-04-01 13:05:26 -0700300 } else {
Charles Chan319d1a22015-11-03 10:42:14 -0800301 ns = new NeighborSet(nextHops, 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);
309 metabuilder.matchVlanId(
310 VlanId.vlanId(SegmentRoutingManager.ASSIGNED_VLAN_NO_SUBNET));
311
312 int nextId = srManager.getNextObjectiveId(deviceId, ns, metabuilder.build());
313 if (nextId <= 0) {
sangho2165d222015-05-01 09:38:25 -0700314 log.warn("No next objective in {} for ns: {}", deviceId, ns);
315 return false;
316 }
317
Srikanth Vavilapalli64505482015-04-21 13:04:13 -0700318 ForwardingObjective.Builder fwdBuilder = DefaultForwardingObjective
319 .builder()
320 .fromApp(srManager.appId)
321 .makePermanent()
Saurav Das4c35fc42015-11-20 15:27:53 -0800322 .nextStep(nextId)
Srikanth Vavilapalli64505482015-04-21 13:04:13 -0700323 .withSelector(selector)
Charles Chan82ab1932016-01-30 23:22:37 -0800324 .withPriority(getPriorityFromPrefix(ipPrefix))
Srikanth Vavilapalli64505482015-04-21 13:04:13 -0700325 .withFlag(ForwardingObjective.Flag.SPECIFIC);
Charles Chanf4586112015-11-09 16:37:23 -0800326 if (treatment != null) {
327 fwdBuilder.withTreatment(treatment);
328 }
Srikanth Vavilapalli64505482015-04-21 13:04:13 -0700329 log.debug("Installing IPv4 forwarding objective "
sangho2165d222015-05-01 09:38:25 -0700330 + "for router IP/subnet {} in switch {}",
Srikanth Vavilapalli64505482015-04-21 13:04:13 -0700331 ipPrefix,
332 deviceId);
Charles Chan1eaf4802016-04-18 13:44:03 -0700333 ObjectiveContext context = new DefaultObjectiveContext(
Saurav Dase0237a32016-05-27 13:54:07 -0700334 (objective) -> log.debug("IP rule for router {} populated in dev:{}",
335 ipPrefix, deviceId),
Charles Chan1eaf4802016-04-18 13:44:03 -0700336 (objective, error) ->
Saurav Dase0237a32016-05-27 13:54:07 -0700337 log.warn("Failed to populate IP rule for router {}: {} in dev:{}",
338 ipPrefix, error, deviceId));
Charles Chan1eaf4802016-04-18 13:44:03 -0700339 srManager.flowObjectiveService.forward(deviceId, fwdBuilder.add(context));
sanghofb7c7292015-04-13 15:15:58 -0700340 rulePopulationCounter.incrementAndGet();
sangho80f11cb2015-04-01 13:05:26 -0700341
342 return true;
343 }
344
sangho80f11cb2015-04-01 13:05:26 -0700345 /**
Charles Chanc22cef32016-04-29 14:38:22 -0700346 * Revokes IP flow rules for the router IP address.
347 *
348 * @param ipPrefix the IP address of the destination router
349 * @return true if all rules are removed successfully, false otherwise
350 */
351 public boolean revokeIpRuleForRouter(IpPrefix ipPrefix) {
352 TrafficSelector.Builder sbuilder = DefaultTrafficSelector.builder();
353 sbuilder.matchIPDst(ipPrefix);
354 sbuilder.matchEthType(Ethernet.TYPE_IPV4);
355 TrafficSelector selector = sbuilder.build();
356 TrafficTreatment dummyTreatment = DefaultTrafficTreatment.builder().build();
357
358 ForwardingObjective.Builder fwdBuilder = DefaultForwardingObjective
359 .builder()
360 .fromApp(srManager.appId)
361 .makePermanent()
362 .withSelector(selector)
363 .withTreatment(dummyTreatment)
364 .withPriority(getPriorityFromPrefix(ipPrefix))
365 .withFlag(ForwardingObjective.Flag.SPECIFIC);
366
367 ObjectiveContext context = new DefaultObjectiveContext(
368 (objective) -> log.debug("IP rule for router {} revoked", ipPrefix),
369 (objective, error) ->
370 log.warn("Failed to revoke IP rule for router {}: {}", ipPrefix, error));
371
372 srManager.deviceService.getAvailableDevices().forEach(device -> {
373 srManager.flowObjectiveService.forward(device.id(), fwdBuilder.remove(context));
374 });
375
376 return true;
377 }
378
379 /**
Saurav Dase0237a32016-05-27 13:54:07 -0700380 * Populates MPLS flow rules in the target device to point towards the
381 * destination device.
sangho80f11cb2015-04-01 13:05:26 -0700382 *
Saurav Dase0237a32016-05-27 13:54:07 -0700383 * @param targetSwId target device ID of the switch to set the rules
sangho80f11cb2015-04-01 13:05:26 -0700384 * @param destSwId destination switch device ID
385 * @param nextHops next hops switch ID list
Pier Ventreadb4ae62016-11-23 09:57:42 -0800386 * @param routerIp the router Ip
sangho80f11cb2015-04-01 13:05:26 -0700387 * @return true if all rules are set successfully, false otherwise
388 */
Saurav Dase0237a32016-05-27 13:54:07 -0700389 public boolean populateMplsRule(DeviceId targetSwId, DeviceId destSwId,
Pier Ventreadb4ae62016-11-23 09:57:42 -0800390 Set<DeviceId> nextHops, IpAddress routerIp) {
Charles Chan319d1a22015-11-03 10:42:14 -0800391 int segmentId;
392 try {
Pier Ventreadb4ae62016-11-23 09:57:42 -0800393 if (routerIp.isIp4()) {
394 segmentId = config.getIPv4SegmentId(destSwId);
395 } else {
396 segmentId = config.getIPv6SegmentId(destSwId);
397 }
Charles Chan319d1a22015-11-03 10:42:14 -0800398 } catch (DeviceConfigNotFoundException e) {
399 log.warn(e.getMessage() + " Aborting populateMplsRule.");
400 return false;
401 }
sangho80f11cb2015-04-01 13:05:26 -0700402
403 TrafficSelector.Builder sbuilder = DefaultTrafficSelector.builder();
Sho SHIMIZU47b8aa22015-09-11 11:19:11 -0700404 List<ForwardingObjective.Builder> fwdObjBuilders = new ArrayList<>();
sangho80f11cb2015-04-01 13:05:26 -0700405
406 // TODO Handle the case of Bos == false
sangho80f11cb2015-04-01 13:05:26 -0700407 sbuilder.matchEthType(Ethernet.MPLS_UNICAST);
Saurav Das4c35fc42015-11-20 15:27:53 -0800408 sbuilder.matchMplsLabel(MplsLabel.mplsLabel(segmentId));
Charles Chande6655c2015-12-23 00:15:11 -0800409 sbuilder.matchMplsBos(true);
Saurav Das4c35fc42015-11-20 15:27:53 -0800410 TrafficSelector selector = sbuilder.build();
sangho80f11cb2015-04-01 13:05:26 -0700411
Saurav Das4c35fc42015-11-20 15:27:53 -0800412 // setup metadata to pass to nextObjective - indicate the vlan on egress
413 // if needed by the switch pipeline. Since mpls next-hops are always to
414 // other neighboring routers, there is no subnet assigned on those ports.
415 TrafficSelector.Builder metabuilder = DefaultTrafficSelector.builder(selector);
416 metabuilder.matchVlanId(
417 VlanId.vlanId(SegmentRoutingManager.ASSIGNED_VLAN_NO_SUBNET));
418
419 // If the next hop is the destination router for the segment, do pop
sangho80f11cb2015-04-01 13:05:26 -0700420 if (nextHops.size() == 1 && destSwId.equals(nextHops.toArray()[0])) {
Srikanth Vavilapalli7cd16712015-05-04 09:48:09 -0700421 log.debug("populateMplsRule: Installing MPLS forwarding objective for "
Saurav Dase0237a32016-05-27 13:54:07 -0700422 + "label {} in switch {} with pop", segmentId, targetSwId);
Srikanth Vavilapalli7cd16712015-05-04 09:48:09 -0700423
Saurav Das4c35fc42015-11-20 15:27:53 -0800424 // bos pop case (php)
Srikanth Vavilapalli64505482015-04-21 13:04:13 -0700425 ForwardingObjective.Builder fwdObjBosBuilder =
Saurav Dase0237a32016-05-27 13:54:07 -0700426 getMplsForwardingObjective(targetSwId,
Srikanth Vavilapalli64505482015-04-21 13:04:13 -0700427 nextHops,
428 true,
Srikanth Vavilapalli64505482015-04-21 13:04:13 -0700429 true,
Pier Ventreadb4ae62016-11-23 09:57:42 -0800430 metabuilder.build(),
431 routerIp);
Saurav Das4c35fc42015-11-20 15:27:53 -0800432 if (fwdObjBosBuilder == null) {
sangho80f11cb2015-04-01 13:05:26 -0700433 return false;
434 }
Saurav Das4c35fc42015-11-20 15:27:53 -0800435 fwdObjBuilders.add(fwdObjBosBuilder);
436
437 // XXX not-bos pop case, SR app multi-label not implemented yet
438 /*ForwardingObjective.Builder fwdObjNoBosBuilder =
439 getMplsForwardingObjective(deviceId,
440 nextHops,
441 true,
442 false);*/
443
sangho80f11cb2015-04-01 13:05:26 -0700444 } else {
Saurav Das4c35fc42015-11-20 15:27:53 -0800445 // next hop is not destination, SR CONTINUE case (swap with self)
Srikanth Vavilapalli7cd16712015-05-04 09:48:09 -0700446 log.debug("Installing MPLS forwarding objective for "
Saurav Dase0237a32016-05-27 13:54:07 -0700447 + "label {} in switch {} without pop", segmentId, targetSwId);
Srikanth Vavilapalli7cd16712015-05-04 09:48:09 -0700448
Saurav Das4c35fc42015-11-20 15:27:53 -0800449 // continue case with bos - this does get triggered in edge routers
450 // and in core routers - driver can handle depending on availability
451 // of MPLS ECMP or not
Srikanth Vavilapalli64505482015-04-21 13:04:13 -0700452 ForwardingObjective.Builder fwdObjBosBuilder =
Saurav Dase0237a32016-05-27 13:54:07 -0700453 getMplsForwardingObjective(targetSwId,
Srikanth Vavilapalli64505482015-04-21 13:04:13 -0700454 nextHops,
455 false,
Saurav Das4c35fc42015-11-20 15:27:53 -0800456 true,
Pier Ventreadb4ae62016-11-23 09:57:42 -0800457 metabuilder.build(),
458 routerIp);
Saurav Das4c35fc42015-11-20 15:27:53 -0800459 if (fwdObjBosBuilder == null) {
sangho80f11cb2015-04-01 13:05:26 -0700460 return false;
461 }
Saurav Das4c35fc42015-11-20 15:27:53 -0800462 fwdObjBuilders.add(fwdObjBosBuilder);
463
464 // XXX continue case with not-bos - SR app multi label not implemented yet
465 // also requires MPLS ECMP
466 /*ForwardingObjective.Builder fwdObjNoBosBuilder =
467 getMplsForwardingObjective(deviceId,
468 nextHops,
469 false,
470 false); */
471
sangho80f11cb2015-04-01 13:05:26 -0700472 }
Saurav Dase0237a32016-05-27 13:54:07 -0700473 // XXX when other cases above are implemented check for validity of
474 // debug messages below
Srikanth Vavilapalli64505482015-04-21 13:04:13 -0700475 for (ForwardingObjective.Builder fwdObjBuilder : fwdObjBuilders) {
476 ((Builder) ((Builder) fwdObjBuilder.fromApp(srManager.appId)
477 .makePermanent()).withSelector(selector)
Charles Chan82ab1932016-01-30 23:22:37 -0800478 .withPriority(SegmentRoutingService.DEFAULT_PRIORITY))
Srikanth Vavilapalli64505482015-04-21 13:04:13 -0700479 .withFlag(ForwardingObjective.Flag.SPECIFIC);
Charles Chan1eaf4802016-04-18 13:44:03 -0700480 ObjectiveContext context = new DefaultObjectiveContext(
Saurav Dase0237a32016-05-27 13:54:07 -0700481 (objective) -> log.debug("MPLS rule {} for SID {} populated in dev:{} ",
482 objective.id(), segmentId, targetSwId),
Charles Chan1eaf4802016-04-18 13:44:03 -0700483 (objective, error) ->
Saurav Dase0237a32016-05-27 13:54:07 -0700484 log.warn("Failed to populate MPLS rule {} for SID {}: {} in dev:{}",
485 objective.id(), segmentId, error, targetSwId));
486 ForwardingObjective fob = fwdObjBuilder.add(context);
487 log.debug("Sending MPLS fwd obj {} for SID {}-> next {} in sw: {}",
488 fob.id(), segmentId, fob.nextId(), targetSwId);
489 srManager.flowObjectiveService.forward(targetSwId, fob);
sanghofb7c7292015-04-13 15:15:58 -0700490 rulePopulationCounter.incrementAndGet();
sangho80f11cb2015-04-01 13:05:26 -0700491 }
492
493 return true;
494 }
495
Saurav Das4c35fc42015-11-20 15:27:53 -0800496 private ForwardingObjective.Builder getMplsForwardingObjective(
497 DeviceId deviceId,
498 Set<DeviceId> nextHops,
499 boolean phpRequired,
500 boolean isBos,
Pier Ventreadb4ae62016-11-23 09:57:42 -0800501 TrafficSelector meta,
502 IpAddress routerIp) {
Saurav Das4c35fc42015-11-20 15:27:53 -0800503
Srikanth Vavilapalli64505482015-04-21 13:04:13 -0700504 ForwardingObjective.Builder fwdBuilder = DefaultForwardingObjective
505 .builder().withFlag(ForwardingObjective.Flag.SPECIFIC);
sangho80f11cb2015-04-01 13:05:26 -0700506
507 TrafficTreatment.Builder tbuilder = DefaultTrafficTreatment.builder();
508
509 if (phpRequired) {
Saurav Das4c35fc42015-11-20 15:27:53 -0800510 // php case - pop should always be flow-action
Srikanth Vavilapalli64505482015-04-21 13:04:13 -0700511 log.debug("getMplsForwardingObjective: php required");
sangho27462c62015-05-14 00:39:53 -0700512 tbuilder.deferred().copyTtlIn();
sangho80f11cb2015-04-01 13:05:26 -0700513 if (isBos) {
Pier Ventreadb4ae62016-11-23 09:57:42 -0800514 if (routerIp.isIp4()) {
515 tbuilder.deferred().popMpls(EthType.EtherType.IPV4.ethType());
516 } else {
517 tbuilder.deferred().popMpls(EthType.EtherType.IPV6.ethType());
518 }
519 tbuilder.decNwTtl();
sangho80f11cb2015-04-01 13:05:26 -0700520 } else {
Saurav Das4c35fc42015-11-20 15:27:53 -0800521 tbuilder.deferred().popMpls(EthType.EtherType.MPLS_UNICAST.ethType())
522 .decMplsTtl();
sangho80f11cb2015-04-01 13:05:26 -0700523 }
524 } else {
Saurav Das4c35fc42015-11-20 15:27:53 -0800525 // swap with self case - SR CONTINUE
Srikanth Vavilapalli64505482015-04-21 13:04:13 -0700526 log.debug("getMplsForwardingObjective: php not required");
sangho27462c62015-05-14 00:39:53 -0700527 tbuilder.deferred().decMplsTtl();
sangho80f11cb2015-04-01 13:05:26 -0700528 }
529
Saurav Das4c35fc42015-11-20 15:27:53 -0800530 // All forwarding is via ECMP group, the metadata informs the driver
531 // that the next-Objective will be used by MPLS flows. In other words,
532 // MPLS ECMP is requested. It is up to the driver to decide if these
533 // packets will be hashed or not.
534 fwdBuilder.withTreatment(tbuilder.build());
535 NeighborSet ns = new NeighborSet(nextHops);
Saurav Dase0237a32016-05-27 13:54:07 -0700536 log.debug("Trying to get a nextObjId for mpls rule on device:{} to ns:{}",
Saurav Das4c35fc42015-11-20 15:27:53 -0800537 deviceId, ns);
538
539 int nextId = srManager.getNextObjectiveId(deviceId, ns, meta);
540 if (nextId <= 0) {
541 log.warn("No next objective in {} for ns: {}", deviceId, ns);
542 return null;
Saurav Dase0237a32016-05-27 13:54:07 -0700543 } else {
544 log.debug("nextObjId found:{} for mpls rule on device:{} to ns:{}",
545 nextId, deviceId, ns);
sangho80f11cb2015-04-01 13:05:26 -0700546 }
547
Saurav Das4c35fc42015-11-20 15:27:53 -0800548 fwdBuilder.nextStep(nextId);
Srikanth Vavilapalli64505482015-04-21 13:04:13 -0700549 return fwdBuilder;
sangho80f11cb2015-04-01 13:05:26 -0700550 }
551
552 /**
Saurav Das9f1c42e2015-10-23 10:51:11 -0700553 * Creates a filtering objective to permit all untagged packets with a
Saurav Das7c305372015-10-28 12:39:42 -0700554 * dstMac corresponding to the router's MAC address. For those pipelines
555 * that need to internally assign vlans to untagged packets, this method
556 * provides per-subnet vlan-ids as metadata.
Saurav Dasc28b3432015-10-30 17:45:38 -0700557 * <p>
558 * Note that the vlan assignment is only done by the master-instance for a switch.
559 * However we send the filtering objective from slave-instances as well, so
560 * that drivers can obtain other information (like Router MAC and IP).
sangho80f11cb2015-04-01 13:05:26 -0700561 *
Saurav Das9f1c42e2015-10-23 10:51:11 -0700562 * @param deviceId the switch dpid for the router
Saurav Dasd1872b02016-12-02 15:43:47 -0800563 * @return PortFilterInfo information about the processed ports
sangho80f11cb2015-04-01 13:05:26 -0700564 */
Saurav Dasd1872b02016-12-02 15:43:47 -0800565 public PortFilterInfo populateRouterMacVlanFilters(DeviceId deviceId) {
Saurav Das7c305372015-10-28 12:39:42 -0700566 log.debug("Installing per-port filtering objective for untagged "
567 + "packets in device {}", deviceId);
Charles Chan319d1a22015-11-03 10:42:14 -0800568
569 MacAddress deviceMac;
570 try {
571 deviceMac = config.getDeviceMac(deviceId);
572 } catch (DeviceConfigNotFoundException e) {
573 log.warn(e.getMessage() + " Aborting populateRouterMacVlanFilters.");
Saurav Dasd1872b02016-12-02 15:43:47 -0800574 return null;
Charles Chan319d1a22015-11-03 10:42:14 -0800575 }
576
Saurav Das07c74602016-04-27 18:35:50 -0700577 List<Port> devPorts = srManager.deviceService.getPorts(deviceId);
Jon Hall31d84782017-01-18 20:15:44 -0800578 if (devPorts == null || devPorts.isEmpty()) {
Saurav Das07c74602016-04-27 18:35:50 -0700579 log.warn("Device {} ports not available. Unable to add MacVlan filters",
580 deviceId);
Saurav Dasd1872b02016-12-02 15:43:47 -0800581 return null;
Saurav Das07c74602016-04-27 18:35:50 -0700582 }
Saurav Dase0237a32016-05-27 13:54:07 -0700583 int disabledPorts = 0, suppressedPorts = 0, filteredPorts = 0;
Saurav Das07c74602016-04-27 18:35:50 -0700584 for (Port port : devPorts) {
Charles Chan1eaf4802016-04-18 13:44:03 -0700585 ConnectPoint connectPoint = new ConnectPoint(deviceId, port.number());
Charles Chan43547ca2016-02-10 20:46:58 -0800586 // TODO: Handles dynamic port events when we are ready for dynamic config
Saurav Dase0237a32016-05-27 13:54:07 -0700587 if (!port.isEnabled()) {
588 disabledPorts++;
589 continue;
590 }
Charles Chandebfea32016-10-24 14:52:01 -0700591
592 boolean isSuppressed = false;
593 SegmentRoutingAppConfig appConfig = srManager.cfgService
594 .getConfig(srManager.appId, SegmentRoutingAppConfig.class);
Saurav Dase0237a32016-05-27 13:54:07 -0700595 if (appConfig != null && appConfig.suppressSubnet().contains(connectPoint)) {
Charles Chandebfea32016-10-24 14:52:01 -0700596 isSuppressed = true;
Saurav Dase0237a32016-05-27 13:54:07 -0700597 suppressedPorts++;
Saurav Dase0237a32016-05-27 13:54:07 -0700598 }
Charles Chandebfea32016-10-24 14:52:01 -0700599
Saurav Dase0237a32016-05-27 13:54:07 -0700600 Ip4Prefix portSubnet = config.getPortSubnet(deviceId, port.number());
Charles Chandebfea32016-10-24 14:52:01 -0700601 VlanId assignedVlan = (portSubnet == null || isSuppressed)
Saurav Dase0237a32016-05-27 13:54:07 -0700602 ? VlanId.vlanId(SegmentRoutingManager.ASSIGNED_VLAN_NO_SUBNET)
603 : srManager.getSubnetAssignedVlanId(deviceId, portSubnet);
Charles Chan319d1a22015-11-03 10:42:14 -0800604
Saurav Dase0237a32016-05-27 13:54:07 -0700605 FilteringObjective.Builder fob = DefaultFilteringObjective.builder();
606 fob.withKey(Criteria.matchInPort(port.number()))
Charles Chan319d1a22015-11-03 10:42:14 -0800607 .addCondition(Criteria.matchEthDst(deviceMac))
Charles Chanb7f75ac2016-01-11 18:28:54 -0800608 .addCondition(Criteria.matchVlanId(VlanId.NONE))
Charles Chan82ab1932016-01-30 23:22:37 -0800609 .withPriority(SegmentRoutingService.DEFAULT_PRIORITY);
Saurav Dase0237a32016-05-27 13:54:07 -0700610 // vlan assignment is valid only if this instance is master
611 if (srManager.mastershipService.isLocalMaster(deviceId)) {
612 TrafficTreatment tt = DefaultTrafficTreatment.builder()
613 .pushVlan().setVlanId(assignedVlan).build();
614 fob.withMeta(tt);
Saurav Das7c305372015-10-28 12:39:42 -0700615 }
Saurav Dase0237a32016-05-27 13:54:07 -0700616 fob.permit().fromApp(srManager.appId);
617 log.debug("Sending filtering objective for dev/port:{}/{}", deviceId, port);
618 filteredPorts++;
619 ObjectiveContext context = new DefaultObjectiveContext(
620 (objective) -> log.debug("Filter for {} populated", connectPoint),
621 (objective, error) ->
622 log.warn("Failed to populate filter for {}: {}", connectPoint, error));
623 srManager.flowObjectiveService.filter(deviceId, fob.add(context));
Saurav Das7c305372015-10-28 12:39:42 -0700624 }
Saurav Dase0237a32016-05-27 13:54:07 -0700625 log.info("Filtering on dev:{}, disabledPorts:{}, suppressedPorts:{}, filteredPorts:{}",
626 deviceId, disabledPorts, suppressedPorts, filteredPorts);
Saurav Dasd1872b02016-12-02 15:43:47 -0800627 return srManager.defaultRoutingHandler.new PortFilterInfo(disabledPorts,
628 suppressedPorts, filteredPorts);
sangho80f11cb2015-04-01 13:05:26 -0700629 }
630
631 /**
Saurav Das9f1c42e2015-10-23 10:51:11 -0700632 * Creates a forwarding objective to punt all IP packets, destined to the
Saurav Dasc28b3432015-10-30 17:45:38 -0700633 * router's port IP addresses, to the controller. Note that the input
Saurav Das9f1c42e2015-10-23 10:51:11 -0700634 * port should not be matched on, as these packets can come from any input.
Saurav Dasc28b3432015-10-30 17:45:38 -0700635 * Furthermore, these are applied only by the master instance.
sangho80f11cb2015-04-01 13:05:26 -0700636 *
Saurav Das9f1c42e2015-10-23 10:51:11 -0700637 * @param deviceId the switch dpid for the router
sangho80f11cb2015-04-01 13:05:26 -0700638 */
Saurav Das9f1c42e2015-10-23 10:51:11 -0700639 public void populateRouterIpPunts(DeviceId deviceId) {
Pier Ventreadb4ae62016-11-23 09:57:42 -0800640 Ip4Address routerIpv4;
641 Ip6Address routerIpv6;
Charles Chan319d1a22015-11-03 10:42:14 -0800642 try {
Pier Ventreadb4ae62016-11-23 09:57:42 -0800643 routerIpv4 = config.getRouterIpv4(deviceId);
644 routerIpv6 = config.getRouterIpv6(deviceId);
Charles Chan319d1a22015-11-03 10:42:14 -0800645 } catch (DeviceConfigNotFoundException e) {
646 log.warn(e.getMessage() + " Aborting populateRouterIpPunts.");
647 return;
648 }
649
Saurav Dasc28b3432015-10-30 17:45:38 -0700650 if (!srManager.mastershipService.isLocalMaster(deviceId)) {
651 log.debug("Not installing port-IP punts - not the master for dev:{} ",
652 deviceId);
653 return;
654 }
Pier Ventreadb4ae62016-11-23 09:57:42 -0800655 Set<IpAddress> allIps = new HashSet<>(config.getPortIPs(deviceId));
656 allIps.add(routerIpv4);
657 if (routerIpv6 != null) {
658 allIps.add(routerIpv6);
659 }
660 for (IpAddress ipaddr : allIps) {
661 TrafficSelector.Builder sbuilder = buildIpSelectorFromIpAddress(ipaddr);
Charles Chan2d0bbcd2017-01-09 11:45:08 -0800662 Optional<DeviceId> optDeviceId = Optional.of(deviceId);
663
664 srManager.packetService.requestPackets(sbuilder.build(),
665 PacketPriority.CONTROL, srManager.appId, optDeviceId);
Saurav Das9f1c42e2015-10-23 10:51:11 -0700666 }
sangho80f11cb2015-04-01 13:05:26 -0700667 }
668
Charles Chanf4586112015-11-09 16:37:23 -0800669 /**
Pier Ventreadb4ae62016-11-23 09:57:42 -0800670 * Method to build IPv4 or IPv6 selector.
671 *
672 * @param addressToMatch the address to match
673 */
674 private TrafficSelector.Builder buildIpSelectorFromIpAddress(IpAddress addressToMatch) {
675 return buildIpSelectorFromIpPrefix(addressToMatch.toIpPrefix());
676 }
677
678 /**
679 * Method to build IPv4 or IPv6 selector.
680 *
681 * @param prefixToMatch the prefix to match
682 */
683 private TrafficSelector.Builder buildIpSelectorFromIpPrefix(IpPrefix prefixToMatch) {
684 TrafficSelector.Builder selectorBuilder = DefaultTrafficSelector.builder();
685 /*
686 * If the prefix is IPv4
687 */
688 if (prefixToMatch.isIp4()) {
689 selectorBuilder.matchEthType(Ethernet.TYPE_IPV4);
690 selectorBuilder.matchIPDst(prefixToMatch.getIp4Prefix());
691 return selectorBuilder;
692 }
693 /*
694 * If the prefix is IPv6
695 */
696 selectorBuilder.matchEthType(Ethernet.TYPE_IPV6);
697 selectorBuilder.matchIPv6Dst(prefixToMatch.getIp6Prefix());
698 return selectorBuilder;
699 }
700
701 /**
Pier Luigib9632ba2017-01-12 18:14:58 -0800702 * Creates forwarding objectives to punt ARP and NDP packets, to the controller.
703 * Furthermore, these are applied only by the master instance. Deferred actions
704 * are not cleared such that packets can be flooded in the cross connect use case
705 *
706 * @param deviceId the switch dpid for the router
707 */
708 public void populateArpNdpPunts(DeviceId deviceId) {
709 /*
710 * We are not the master just skip.
711 */
712 if (!srManager.mastershipService.isLocalMaster(deviceId)) {
713 log.debug("Not installing ARP/NDP punts - not the master for dev:{} ",
714 deviceId);
715 return;
716 }
717
718 // We punt all ARP packets towards the controller.
719 ForwardingObjective puntFwd = puntArpFwdObjective()
720 .add(new ObjectiveContext() {
721 @Override
722 public void onError(Objective objective, ObjectiveError error) {
723 log.warn("Failed to install packet request for ARP to {}: {}",
724 deviceId, error);
725 }
726 });
727 srManager.flowObjectiveService.forward(deviceId, puntFwd);
728
Pier Luigib9632ba2017-01-12 18:14:58 -0800729 // We punt all NDP packets towards the controller.
Pier Luigib9632ba2017-01-12 18:14:58 -0800730 puntFwd = puntNdpFwdObjective()
731 .add(new ObjectiveContext() {
732 @Override
733 public void onError(Objective objective, ObjectiveError error) {
734 log.warn("Failed to install packet request for NDP to {}: {}",
735 deviceId, error);
736 }
737 });
738 srManager.flowObjectiveService.forward(deviceId, puntFwd);
Pier Luigib9632ba2017-01-12 18:14:58 -0800739 }
740
741 private ForwardingObjective.Builder fwdObjBuilder(TrafficSelector selector) {
742
743 TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder();
744 tBuilder.punt();
745
746 return DefaultForwardingObjective.builder()
747 .withPriority(PacketPriority.CONTROL.priorityValue())
748 .withSelector(selector)
749 .fromApp(srManager.appId)
750 .withFlag(ForwardingObjective.Flag.VERSATILE)
751 .withTreatment(tBuilder.build())
752 .makePermanent();
753 }
754
755 private ForwardingObjective.Builder puntArpFwdObjective() {
756
757 TrafficSelector.Builder sBuilder = DefaultTrafficSelector.builder();
758 sBuilder.matchEthType(TYPE_ARP);
759
760 return fwdObjBuilder(sBuilder.build());
761 }
762
763 private ForwardingObjective.Builder puntNdpFwdObjective() {
764
765 TrafficSelector.Builder sBuilder = DefaultTrafficSelector.builder();
766 sBuilder.matchEthType(TYPE_IPV6)
767 .matchIPProtocol(PROTOCOL_ICMP6)
768 .matchIcmpv6Type(NEIGHBOR_SOLICITATION)
769 .build();
770
771 return fwdObjBuilder(sBuilder.build());
772 }
773
774 /**
Charles Chanf4586112015-11-09 16:37:23 -0800775 * Populates a forwarding objective to send packets that miss other high
776 * priority Bridging Table entries to a group that contains all ports of
777 * its subnet.
778 *
779 * Note: We assume that packets sending from the edge switches to the hosts
780 * have untagged VLAN.
781 * The VLAN tag will be popped later in the flooding group.
782 *
783 * @param deviceId switch ID to set the rules
784 */
785 public void populateSubnetBroadcastRule(DeviceId deviceId) {
786 config.getSubnets(deviceId).forEach(subnet -> {
Charles Chanbbd004c2016-02-16 23:14:49 -0800787 if (subnet.prefixLength() == 0 ||
788 subnet.prefixLength() == IpPrefix.MAX_INET_MASK_LENGTH) {
789 return;
790 }
Charles Chanf4586112015-11-09 16:37:23 -0800791 int nextId = srManager.getSubnetNextObjectiveId(deviceId, subnet);
792 VlanId vlanId = srManager.getSubnetAssignedVlanId(deviceId, subnet);
793
Saurav Das2d94d312015-11-24 23:21:05 -0800794 if (nextId < 0 || vlanId == null) {
Charles Chanbbd004c2016-02-16 23:14:49 -0800795 log.error("Cannot install subnet {} broadcast rule in dev:{} due"
796 + "to vlanId:{} or nextId:{}", subnet, deviceId, vlanId, nextId);
Saurav Das2d94d312015-11-24 23:21:05 -0800797 return;
798 }
799
Charles Chanf4586112015-11-09 16:37:23 -0800800 /* Driver should treat objective with MacAddress.NONE as the
801 * subnet broadcast rule
802 */
803 TrafficSelector.Builder sbuilder = DefaultTrafficSelector.builder();
804 sbuilder.matchVlanId(vlanId);
805 sbuilder.matchEthDst(MacAddress.NONE);
806
807 ForwardingObjective.Builder fob = DefaultForwardingObjective.builder();
808 fob.withFlag(Flag.SPECIFIC)
809 .withSelector(sbuilder.build())
810 .nextStep(nextId)
Charles Chan82ab1932016-01-30 23:22:37 -0800811 .withPriority(SegmentRoutingService.FLOOD_PRIORITY)
Charles Chanf4586112015-11-09 16:37:23 -0800812 .fromApp(srManager.appId)
813 .makePermanent();
Charles Chan1eaf4802016-04-18 13:44:03 -0700814 ObjectiveContext context = new DefaultObjectiveContext(
815 (objective) -> log.debug("Subnet broadcast rule for {} populated", subnet),
816 (objective, error) ->
817 log.warn("Failed to populate subnet broadcast rule for {}: {}", subnet, error));
818 srManager.flowObjectiveService.forward(deviceId, fob.add(context));
Charles Chanf4586112015-11-09 16:37:23 -0800819 });
820 }
821
Charles Chan82ab1932016-01-30 23:22:37 -0800822 private int getPriorityFromPrefix(IpPrefix prefix) {
823 return (prefix.isIp4()) ?
824 2000 * prefix.prefixLength() + SegmentRoutingService.MIN_IP_PRIORITY :
825 500 * prefix.prefixLength() + SegmentRoutingService.MIN_IP_PRIORITY;
Srikanth Vavilapalli8c83f1d2015-05-22 13:47:31 -0700826 }
sangho80f11cb2015-04-01 13:05:26 -0700827}