blob: 38d8aacc96488dda259df0d688704de77d95d20d [file] [log] [blame]
Brian O'Connor7cbbbb72016-04-09 02:13:23 -07001/*
Brian O'Connora09fe5b2017-08-03 21:12:30 -07002 * Copyright 2016-present Open Networking Foundation
Brian O'Connor7cbbbb72016-04-09 02:13:23 -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 */
Charles Chan5270ed02016-01-30 23:22:37 -080016package org.onosproject.segmentrouting;
17
18import com.google.common.collect.ImmutableSet;
Andrea Campanellad980c6d2018-04-30 11:48:55 +020019import com.google.common.collect.Sets;
20import org.onlab.packet.IpPrefix;
Charles Chan5270ed02016-01-30 23:22:37 -080021import org.onlab.packet.MacAddress;
22import org.onosproject.net.DeviceId;
23import org.onosproject.net.PortNumber;
24import org.onosproject.net.config.NetworkConfigEvent;
25import org.onosproject.net.device.DeviceService;
26import org.onosproject.net.flow.criteria.Criteria;
27import org.onosproject.net.flowobjective.DefaultFilteringObjective;
Charles Chand2990362016-04-18 13:44:03 -070028import org.onosproject.net.flowobjective.DefaultObjectiveContext;
Charles Chan5270ed02016-01-30 23:22:37 -080029import org.onosproject.net.flowobjective.FilteringObjective;
Charles Chand2990362016-04-18 13:44:03 -070030import org.onosproject.net.flowobjective.ObjectiveContext;
Charles Chan5270ed02016-01-30 23:22:37 -080031import org.onosproject.segmentrouting.config.DeviceConfigNotFoundException;
32import org.onosproject.segmentrouting.config.SegmentRoutingAppConfig;
33import org.slf4j.Logger;
34import org.slf4j.LoggerFactory;
35
36import java.util.HashSet;
37import java.util.Set;
38
39/**
Charles Chanfc5c7802016-05-17 13:13:55 -070040 * Handles Segment Routing app config events.
Charles Chan5270ed02016-01-30 23:22:37 -080041 */
Charles Chanfc5c7802016-05-17 13:13:55 -070042public class AppConfigHandler {
43 private static final Logger log = LoggerFactory.getLogger(AppConfigHandler.class);
Charles Chan5270ed02016-01-30 23:22:37 -080044 private final SegmentRoutingManager srManager;
45 private final DeviceService deviceService;
46
47 /**
Charles Chanfc5c7802016-05-17 13:13:55 -070048 * Constructs Segment Routing App Config Handler.
Charles Chan5270ed02016-01-30 23:22:37 -080049 *
50 * @param srManager instance of {@link SegmentRoutingManager}
51 */
Charles Chanfc5c7802016-05-17 13:13:55 -070052 public AppConfigHandler(SegmentRoutingManager srManager) {
Charles Chan5270ed02016-01-30 23:22:37 -080053 this.srManager = srManager;
54 this.deviceService = srManager.deviceService;
55 }
56
57 /**
Charles Chanfc5c7802016-05-17 13:13:55 -070058 * Processes Segment Routing App Config added event.
Charles Chan5270ed02016-01-30 23:22:37 -080059 *
60 * @param event network config added event
61 */
Charles Chanfc5c7802016-05-17 13:13:55 -070062 protected void processAppConfigAdded(NetworkConfigEvent event) {
Pier Ventre98161782016-10-31 15:00:01 -070063 log.info("Processing AppConfig CONFIG_ADDED");
Charles Chan5270ed02016-01-30 23:22:37 -080064 SegmentRoutingAppConfig config = (SegmentRoutingAppConfig) event.config().get();
65 deviceService.getAvailableDevices().forEach(device -> {
66 populateVRouter(device.id(), getMacAddresses(config));
Andrea Campanellad980c6d2018-04-30 11:48:55 +020067 config.blackholeIPs().forEach(ipPrefix -> {
68 srManager.routingRulePopulator.populateDefaultRouteBlackhole(device.id(), ipPrefix);
69 });
Charles Chan5270ed02016-01-30 23:22:37 -080070 });
71 }
72
73 /**
Charles Chanfc5c7802016-05-17 13:13:55 -070074 * Processes Segment Routing App Config updated event.
Charles Chan5270ed02016-01-30 23:22:37 -080075 *
76 * @param event network config updated event
77 */
Charles Chanfc5c7802016-05-17 13:13:55 -070078 protected void processAppConfigUpdated(NetworkConfigEvent event) {
Pier Ventre98161782016-10-31 15:00:01 -070079 log.info("Processing AppConfig CONFIG_UPDATED");
Charles Chan5270ed02016-01-30 23:22:37 -080080 SegmentRoutingAppConfig config = (SegmentRoutingAppConfig) event.config().get();
81 SegmentRoutingAppConfig prevConfig = (SegmentRoutingAppConfig) event.prevConfig().get();
82 deviceService.getAvailableDevices().forEach(device -> {
Charles Chand55e84d2016-03-30 17:54:24 -070083 Set<MacAddress> macAddresses = new HashSet<>(getMacAddresses(config));
84 Set<MacAddress> prevMacAddresses = new HashSet<>(getMacAddresses(prevConfig));
Charles Chan5270ed02016-01-30 23:22:37 -080085 // Avoid removing and re-adding unchanged MAC addresses since
86 // FlowObjective does not guarantee the execution order.
87 Set<MacAddress> sameMacAddresses = new HashSet<>(macAddresses);
88 sameMacAddresses.retainAll(prevMacAddresses);
89 macAddresses.removeAll(sameMacAddresses);
90 prevMacAddresses.removeAll(sameMacAddresses);
91
92 revokeVRouter(device.id(), prevMacAddresses);
93 populateVRouter(device.id(), macAddresses);
Andrea Campanellad980c6d2018-04-30 11:48:55 +020094 Set<IpPrefix> toRemove = Sets.difference(prevConfig.blackholeIPs(), config.blackholeIPs());
95 toRemove.forEach(ipPrefix -> {
96 srManager.routingRulePopulator.removeDefaultRouteBlackhole(device.id(), ipPrefix);
97 });
98 Set<IpPrefix> toAdd = Sets.difference(config.blackholeIPs(), prevConfig.blackholeIPs());
99 toAdd.forEach(ipPrefix -> {
100 srManager.routingRulePopulator.populateDefaultRouteBlackhole(device.id(), ipPrefix);
101 });
Charles Chan5270ed02016-01-30 23:22:37 -0800102 });
103
104 }
105
106 /**
Charles Chanfc5c7802016-05-17 13:13:55 -0700107 * Processes Segment Routing App Config removed event.
Charles Chan5270ed02016-01-30 23:22:37 -0800108 *
109 * @param event network config removed event
110 */
Charles Chanfc5c7802016-05-17 13:13:55 -0700111 protected void processAppConfigRemoved(NetworkConfigEvent event) {
Pier Ventre98161782016-10-31 15:00:01 -0700112 log.info("Processing AppConfig CONFIG_REMOVED");
Charles Chan5270ed02016-01-30 23:22:37 -0800113 SegmentRoutingAppConfig prevConfig = (SegmentRoutingAppConfig) event.prevConfig().get();
114 deviceService.getAvailableDevices().forEach(device -> {
115 revokeVRouter(device.id(), getMacAddresses(prevConfig));
Andrea Campanellad980c6d2018-04-30 11:48:55 +0200116 prevConfig.blackholeIPs().forEach(ipPrefix -> {
117 srManager.routingRulePopulator.removeDefaultRouteBlackhole(device.id(), ipPrefix);
118 });
Charles Chan5270ed02016-01-30 23:22:37 -0800119 });
120 }
121
122 /**
Andrea Campanellad980c6d2018-04-30 11:48:55 +0200123 * Populates initial vRouter and blackhole rules.
Charles Chan5270ed02016-01-30 23:22:37 -0800124 *
125 * @param deviceId device ID
126 */
Charles Chan03a73e02016-10-24 14:52:01 -0700127 public void init(DeviceId deviceId) {
Charles Chan5270ed02016-01-30 23:22:37 -0800128 SegmentRoutingAppConfig config =
129 srManager.cfgService.getConfig(srManager.appId, SegmentRoutingAppConfig.class);
130 populateVRouter(deviceId, getMacAddresses(config));
Andrea Campanella1487dec2018-05-10 19:18:48 +0200131 if (config != null) {
132 config.blackholeIPs().forEach(ipPrefix -> {
133 srManager.routingRulePopulator.populateDefaultRouteBlackhole(deviceId, ipPrefix);
134 });
135 }
Charles Chan5270ed02016-01-30 23:22:37 -0800136 }
137
138 private void populateVRouter(DeviceId deviceId, Set<MacAddress> pendingAdd) {
139 if (!isEdge(deviceId)) {
140 return;
141 }
142 getVRouterFlowObjBuilders(pendingAdd).forEach(foBuilder -> {
Charles Chand2990362016-04-18 13:44:03 -0700143 ObjectiveContext context = new DefaultObjectiveContext(
144 (objective) -> log.debug("vRouterMac filter for {} populated", pendingAdd),
145 (objective, error) ->
146 log.warn("Failed to populate vRouterMac filter for {}: {}", pendingAdd, error));
147 srManager.flowObjectiveService.filter(deviceId, foBuilder.add(context));
Charles Chan5270ed02016-01-30 23:22:37 -0800148 });
149 }
150
151 private void revokeVRouter(DeviceId deviceId, Set<MacAddress> pendingRemove) {
152 if (!isEdge(deviceId)) {
153 return;
154 }
155 getVRouterFlowObjBuilders(pendingRemove).forEach(foBuilder -> {
Charles Chand2990362016-04-18 13:44:03 -0700156 ObjectiveContext context = new DefaultObjectiveContext(
157 (objective) -> log.debug("vRouterMac filter for {} revoked", pendingRemove),
158 (objective, error) ->
159 log.warn("Failed to revoke vRouterMac filter for {}: {}", pendingRemove, error));
160 srManager.flowObjectiveService.filter(deviceId, foBuilder.remove(context));
Charles Chan5270ed02016-01-30 23:22:37 -0800161 });
162 }
163
164 private Set<FilteringObjective.Builder> getVRouterFlowObjBuilders(Set<MacAddress> macAddresses) {
165 ImmutableSet.Builder<FilteringObjective.Builder> setBuilder = ImmutableSet.builder();
166 macAddresses.forEach(macAddress -> {
167 FilteringObjective.Builder fobuilder = DefaultFilteringObjective.builder();
168 fobuilder.withKey(Criteria.matchInPort(PortNumber.ANY))
169 .addCondition(Criteria.matchEthDst(macAddress))
170 .permit()
171 .withPriority(SegmentRoutingService.DEFAULT_PRIORITY)
172 .fromApp(srManager.appId);
173 setBuilder.add(fobuilder);
174 });
175 return setBuilder.build();
176 }
177
178 private Set<MacAddress> getMacAddresses(SegmentRoutingAppConfig config) {
179 if (config == null) {
180 return ImmutableSet.of();
181 }
Charles Chan2196a922016-03-07 00:49:33 -0800182 return ImmutableSet.copyOf(config.vRouterMacs());
Charles Chan5270ed02016-01-30 23:22:37 -0800183 }
184
185 private boolean isEdge(DeviceId deviceId) {
186 try {
187 if (srManager.deviceConfiguration.isEdgeDevice(deviceId)) {
188 return true;
189 }
Andrea Campanellad980c6d2018-04-30 11:48:55 +0200190 } catch (DeviceConfigNotFoundException e) {
191 log.warn("Device configuration for {} is not present.", deviceId);
192 }
Charles Chan5270ed02016-01-30 23:22:37 -0800193 return false;
194 }
195}