blob: e9a4706ee1355efd92b7b25420f347338e3849a8 [file] [log] [blame]
Charles Chand2990362016-04-18 13:44:03 -07001/*
2 * Copyright 2016-present Open Networking Laboratory
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package org.onosproject.segmentrouting;
18
19import org.onlab.packet.Ip4Prefix;
20import org.onlab.packet.IpAddress;
21import org.onlab.packet.MacAddress;
22import org.onlab.packet.VlanId;
23import org.onosproject.core.CoreService;
24import org.onosproject.net.ConnectPoint;
25import org.onosproject.net.DeviceId;
26import org.onosproject.net.PortNumber;
27import org.onosproject.net.flow.DefaultTrafficSelector;
28import org.onosproject.net.flow.DefaultTrafficTreatment;
29import org.onosproject.net.flow.TrafficSelector;
30import org.onosproject.net.flow.TrafficTreatment;
31import org.onosproject.net.flowobjective.DefaultForwardingObjective;
32import org.onosproject.net.flowobjective.DefaultObjectiveContext;
33import org.onosproject.net.flowobjective.FlowObjectiveService;
34import org.onosproject.net.flowobjective.ForwardingObjective;
35import org.onosproject.net.flowobjective.ObjectiveContext;
36import org.onosproject.net.host.HostEvent;
37import org.onosproject.net.host.HostService;
38import org.slf4j.Logger;
39import org.slf4j.LoggerFactory;
40
41import java.util.Set;
42
43/**
44 * Handles host-related events.
45 */
46public class HostHandler {
47 private static final Logger log = LoggerFactory.getLogger(HostHandler.class);
48 private final SegmentRoutingManager srManager;
49 private CoreService coreService;
50 private HostService hostService;
51 private FlowObjectiveService flowObjectiveService;
52
53 /**
54 * Constructs the HostHandler.
55 *
56 * @param srManager Segment Routing manager
57 */
58 public HostHandler(SegmentRoutingManager srManager) {
59 this.srManager = srManager;
60 coreService = srManager.coreService;
61 hostService = srManager.hostService;
62 flowObjectiveService = srManager.flowObjectiveService;
63 }
64
Saurav Das59232cf2016-04-27 18:35:50 -070065 protected void readInitialHosts(DeviceId devId) {
Charles Chand2990362016-04-18 13:44:03 -070066 hostService.getHosts().forEach(host -> {
Saurav Das59232cf2016-04-27 18:35:50 -070067 DeviceId deviceId = host.location().deviceId();
68 if (!deviceId.equals(devId)) {
69 // not an attached host to this device
70 return;
71 }
Charles Chand2990362016-04-18 13:44:03 -070072 MacAddress mac = host.mac();
73 VlanId vlanId = host.vlan();
Charles Chand2990362016-04-18 13:44:03 -070074 PortNumber port = host.location().port();
75 Set<IpAddress> ips = host.ipAddresses();
Saurav Das59232cf2016-04-27 18:35:50 -070076 log.debug("Attached Host {}/{} is added at {}:{}", mac, vlanId,
77 deviceId, port);
Charles Chand2990362016-04-18 13:44:03 -070078
79 // Populate bridging table entry
80 ForwardingObjective.Builder fob =
81 getForwardingObjectiveBuilder(deviceId, mac, vlanId, port);
Saurav Das59232cf2016-04-27 18:35:50 -070082 if (fob == null) {
83 log.warn("Aborting host bridging & routing table entries due "
84 + "to error for dev:{} host:{}", deviceId, host);
85 return;
86 }
Charles Chand2990362016-04-18 13:44:03 -070087 ObjectiveContext context = new DefaultObjectiveContext(
88 (objective) -> log.debug("Host rule for {} populated", host),
89 (objective, error) ->
90 log.warn("Failed to populate host rule for {}: {}", host, error));
91 flowObjectiveService.forward(deviceId, fob.add(context));
92
93 // Populate IP table entry
94 ips.forEach(ip -> {
95 if (ip.isIp4()) {
96 srManager.routingRulePopulator.populateIpRuleForHost(
97 deviceId, ip.getIp4Address(), mac, port);
98 }
99 });
100 });
101 }
102
103 private ForwardingObjective.Builder getForwardingObjectiveBuilder(
104 DeviceId deviceId, MacAddress mac, VlanId vlanId,
105 PortNumber outport) {
106 // Get assigned VLAN for the subnet
107 VlanId outvlan = null;
108 Ip4Prefix subnet = srManager.deviceConfiguration.getPortSubnet(deviceId, outport);
109 if (subnet == null) {
110 outvlan = VlanId.vlanId(SegmentRoutingManager.ASSIGNED_VLAN_NO_SUBNET);
111 } else {
112 outvlan = srManager.getSubnetAssignedVlanId(deviceId, subnet);
113 }
114
115 // match rule
116 TrafficSelector.Builder sbuilder = DefaultTrafficSelector.builder();
117 sbuilder.matchEthDst(mac);
118 /*
119 * Note: for untagged packets, match on the assigned VLAN.
120 * for tagged packets, match on its incoming VLAN.
121 */
122 if (vlanId.equals(VlanId.NONE)) {
123 sbuilder.matchVlanId(outvlan);
124 } else {
125 sbuilder.matchVlanId(vlanId);
126 }
127
128 TrafficTreatment.Builder tbuilder = DefaultTrafficTreatment.builder();
129 tbuilder.immediate().popVlan();
130 tbuilder.immediate().setOutput(outport);
131
132 // for switch pipelines that need it, provide outgoing vlan as metadata
133 TrafficSelector meta = DefaultTrafficSelector.builder()
134 .matchVlanId(outvlan).build();
135
136 // All forwarding is via Groups. Drivers can re-purpose to flow-actions if needed.
137 int portNextObjId = srManager.getPortNextObjectiveId(deviceId, outport,
138 tbuilder.build(),
139 meta);
Saurav Das59232cf2016-04-27 18:35:50 -0700140 if (portNextObjId == -1) {
141 // warning log will come from getPortNextObjective method
142 return null;
143 }
Charles Chand2990362016-04-18 13:44:03 -0700144
145 return DefaultForwardingObjective.builder()
146 .withFlag(ForwardingObjective.Flag.SPECIFIC)
147 .withSelector(sbuilder.build())
148 .nextStep(portNextObjId)
149 .withPriority(100)
150 .fromApp(srManager.appId)
151 .makePermanent();
152 }
153
154 protected void processHostAddedEvent(HostEvent event) {
155 MacAddress mac = event.subject().mac();
156 VlanId vlanId = event.subject().vlan();
157 DeviceId deviceId = event.subject().location().deviceId();
158 PortNumber port = event.subject().location().port();
159 Set<IpAddress> ips = event.subject().ipAddresses();
160 log.info("Host {}/{} is added at {}:{}", mac, vlanId, deviceId, port);
161
162 if (!srManager.deviceConfiguration.suppressHost()
163 .contains(new ConnectPoint(deviceId, port))) {
164 // Populate bridging table entry
165 log.debug("Populate L2 table entry for host {} at {}:{}",
166 mac, deviceId, port);
167 ForwardingObjective.Builder fob =
168 getForwardingObjectiveBuilder(deviceId, mac, vlanId, port);
169 ObjectiveContext context = new DefaultObjectiveContext(
170 (objective) -> log.debug("Host rule for {} populated", event.subject()),
171 (objective, error) ->
172 log.warn("Failed to populate host rule for {}: {}", event.subject(), error));
173 flowObjectiveService.forward(deviceId, fob.add(context));
174
175 // Populate IP table entry
176 ips.forEach(ip -> {
177 if (ip.isIp4()) {
178 srManager.routingRulePopulator.populateIpRuleForHost(
179 deviceId, ip.getIp4Address(), mac, port);
180 }
181 });
182 }
183 }
184
185 protected void processHostRemoveEvent(HostEvent event) {
186 MacAddress mac = event.subject().mac();
187 VlanId vlanId = event.subject().vlan();
188 DeviceId deviceId = event.subject().location().deviceId();
189 PortNumber port = event.subject().location().port();
190 Set<IpAddress> ips = event.subject().ipAddresses();
191 log.debug("Host {}/{} is removed from {}:{}", mac, vlanId, deviceId, port);
192
193 if (!srManager.deviceConfiguration.suppressHost()
194 .contains(new ConnectPoint(deviceId, port))) {
195 // Revoke bridging table entry
196 ForwardingObjective.Builder fob =
197 getForwardingObjectiveBuilder(deviceId, mac, vlanId, port);
198 ObjectiveContext context = new DefaultObjectiveContext(
199 (objective) -> log.debug("Host rule for {} revoked", event.subject()),
200 (objective, error) ->
201 log.warn("Failed to revoke host rule for {}: {}", event.subject(), error));
202 flowObjectiveService.forward(deviceId, fob.remove(context));
203
204 // Revoke IP table entry
205 ips.forEach(ip -> {
206 if (ip.isIp4()) {
207 srManager.routingRulePopulator.revokeIpRuleForHost(
208 deviceId, ip.getIp4Address(), mac, port);
209 }
210 });
211 }
212 }
213
214 protected void processHostMovedEvent(HostEvent event) {
215 MacAddress mac = event.subject().mac();
216 VlanId vlanId = event.subject().vlan();
217 DeviceId prevDeviceId = event.prevSubject().location().deviceId();
218 PortNumber prevPort = event.prevSubject().location().port();
219 Set<IpAddress> prevIps = event.prevSubject().ipAddresses();
220 DeviceId newDeviceId = event.subject().location().deviceId();
221 PortNumber newPort = event.subject().location().port();
222 Set<IpAddress> newIps = event.subject().ipAddresses();
223 log.debug("Host {}/{} is moved from {}:{} to {}:{}",
224 mac, vlanId, prevDeviceId, prevPort, newDeviceId, newPort);
225
226 if (!srManager.deviceConfiguration.suppressHost()
227 .contains(new ConnectPoint(prevDeviceId, prevPort))) {
228 // Revoke previous bridging table entry
229 ForwardingObjective.Builder prevFob =
230 getForwardingObjectiveBuilder(prevDeviceId, mac, vlanId, prevPort);
231 ObjectiveContext context = new DefaultObjectiveContext(
232 (objective) -> log.debug("Host rule for {} revoked", event.subject()),
233 (objective, error) ->
234 log.warn("Failed to revoke host rule for {}: {}", event.subject(), error));
235 flowObjectiveService.forward(prevDeviceId, prevFob.remove(context));
236
237 // Revoke previous IP table entry
238 prevIps.forEach(ip -> {
239 if (ip.isIp4()) {
240 srManager.routingRulePopulator.revokeIpRuleForHost(
241 prevDeviceId, ip.getIp4Address(), mac, prevPort);
242 }
243 });
244 }
245
246 if (!srManager.deviceConfiguration.suppressHost()
247 .contains(new ConnectPoint(newDeviceId, newPort))) {
248 // Populate new bridging table entry
249 ForwardingObjective.Builder newFob =
250 getForwardingObjectiveBuilder(newDeviceId, mac, vlanId, newPort);
251 ObjectiveContext context = new DefaultObjectiveContext(
252 (objective) -> log.debug("Host rule for {} populated", event.subject()),
253 (objective, error) ->
254 log.warn("Failed to populate host rule for {}: {}", event.subject(), error));
255 flowObjectiveService.forward(newDeviceId, newFob.add(context));
256
257 // Populate new IP table entry
258 newIps.forEach(ip -> {
259 if (ip.isIp4()) {
260 srManager.routingRulePopulator.populateIpRuleForHost(
261 newDeviceId, ip.getIp4Address(), mac, newPort);
262 }
263 });
264 }
265 }
266
267 protected void processHostUpdatedEvent(HostEvent event) {
268 MacAddress mac = event.subject().mac();
269 VlanId vlanId = event.subject().vlan();
270 DeviceId prevDeviceId = event.prevSubject().location().deviceId();
271 PortNumber prevPort = event.prevSubject().location().port();
272 Set<IpAddress> prevIps = event.prevSubject().ipAddresses();
273 DeviceId newDeviceId = event.subject().location().deviceId();
274 PortNumber newPort = event.subject().location().port();
275 Set<IpAddress> newIps = event.subject().ipAddresses();
276 log.debug("Host {}/{} is updated", mac, vlanId);
277
278 if (!srManager.deviceConfiguration.suppressHost()
279 .contains(new ConnectPoint(prevDeviceId, prevPort))) {
280 // Revoke previous IP table entry
281 prevIps.forEach(ip -> {
282 if (ip.isIp4()) {
283 srManager.routingRulePopulator.revokeIpRuleForHost(
284 prevDeviceId, ip.getIp4Address(), mac, prevPort);
285 }
286 });
287 }
288
289 if (!srManager.deviceConfiguration.suppressHost()
290 .contains(new ConnectPoint(newDeviceId, newPort))) {
291 // Populate new IP table entry
292 newIps.forEach(ip -> {
293 if (ip.isIp4()) {
294 srManager.routingRulePopulator.populateIpRuleForHost(
295 newDeviceId, ip.getIp4Address(), mac, newPort);
296 }
297 });
298 }
299 }
300}