blob: 0b1621ec9037978c4d1cdc393be89f15c6e1c701 [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
65 protected void readInitialHosts() {
66 hostService.getHosts().forEach(host -> {
67 MacAddress mac = host.mac();
68 VlanId vlanId = host.vlan();
69 DeviceId deviceId = host.location().deviceId();
70 PortNumber port = host.location().port();
71 Set<IpAddress> ips = host.ipAddresses();
72 log.debug("Host {}/{} is added at {}:{}", mac, vlanId, deviceId, port);
73
74 // Populate bridging table entry
75 ForwardingObjective.Builder fob =
76 getForwardingObjectiveBuilder(deviceId, mac, vlanId, port);
77 ObjectiveContext context = new DefaultObjectiveContext(
78 (objective) -> log.debug("Host rule for {} populated", host),
79 (objective, error) ->
80 log.warn("Failed to populate host rule for {}: {}", host, error));
81 flowObjectiveService.forward(deviceId, fob.add(context));
82
83 // Populate IP table entry
84 ips.forEach(ip -> {
85 if (ip.isIp4()) {
86 srManager.routingRulePopulator.populateIpRuleForHost(
87 deviceId, ip.getIp4Address(), mac, port);
88 }
89 });
90 });
91 }
92
93 private ForwardingObjective.Builder getForwardingObjectiveBuilder(
94 DeviceId deviceId, MacAddress mac, VlanId vlanId,
95 PortNumber outport) {
96 // Get assigned VLAN for the subnet
97 VlanId outvlan = null;
98 Ip4Prefix subnet = srManager.deviceConfiguration.getPortSubnet(deviceId, outport);
99 if (subnet == null) {
100 outvlan = VlanId.vlanId(SegmentRoutingManager.ASSIGNED_VLAN_NO_SUBNET);
101 } else {
102 outvlan = srManager.getSubnetAssignedVlanId(deviceId, subnet);
103 }
104
105 // match rule
106 TrafficSelector.Builder sbuilder = DefaultTrafficSelector.builder();
107 sbuilder.matchEthDst(mac);
108 /*
109 * Note: for untagged packets, match on the assigned VLAN.
110 * for tagged packets, match on its incoming VLAN.
111 */
112 if (vlanId.equals(VlanId.NONE)) {
113 sbuilder.matchVlanId(outvlan);
114 } else {
115 sbuilder.matchVlanId(vlanId);
116 }
117
118 TrafficTreatment.Builder tbuilder = DefaultTrafficTreatment.builder();
119 tbuilder.immediate().popVlan();
120 tbuilder.immediate().setOutput(outport);
121
122 // for switch pipelines that need it, provide outgoing vlan as metadata
123 TrafficSelector meta = DefaultTrafficSelector.builder()
124 .matchVlanId(outvlan).build();
125
126 // All forwarding is via Groups. Drivers can re-purpose to flow-actions if needed.
127 int portNextObjId = srManager.getPortNextObjectiveId(deviceId, outport,
128 tbuilder.build(),
129 meta);
130
131 return DefaultForwardingObjective.builder()
132 .withFlag(ForwardingObjective.Flag.SPECIFIC)
133 .withSelector(sbuilder.build())
134 .nextStep(portNextObjId)
135 .withPriority(100)
136 .fromApp(srManager.appId)
137 .makePermanent();
138 }
139
140 protected void processHostAddedEvent(HostEvent event) {
141 MacAddress mac = event.subject().mac();
142 VlanId vlanId = event.subject().vlan();
143 DeviceId deviceId = event.subject().location().deviceId();
144 PortNumber port = event.subject().location().port();
145 Set<IpAddress> ips = event.subject().ipAddresses();
146 log.info("Host {}/{} is added at {}:{}", mac, vlanId, deviceId, port);
147
148 if (!srManager.deviceConfiguration.suppressHost()
149 .contains(new ConnectPoint(deviceId, port))) {
150 // Populate bridging table entry
151 log.debug("Populate L2 table entry for host {} at {}:{}",
152 mac, deviceId, port);
153 ForwardingObjective.Builder fob =
154 getForwardingObjectiveBuilder(deviceId, mac, vlanId, port);
155 ObjectiveContext context = new DefaultObjectiveContext(
156 (objective) -> log.debug("Host rule for {} populated", event.subject()),
157 (objective, error) ->
158 log.warn("Failed to populate host rule for {}: {}", event.subject(), error));
159 flowObjectiveService.forward(deviceId, fob.add(context));
160
161 // Populate IP table entry
162 ips.forEach(ip -> {
163 if (ip.isIp4()) {
164 srManager.routingRulePopulator.populateIpRuleForHost(
165 deviceId, ip.getIp4Address(), mac, port);
166 }
167 });
168 }
169 }
170
171 protected void processHostRemoveEvent(HostEvent event) {
172 MacAddress mac = event.subject().mac();
173 VlanId vlanId = event.subject().vlan();
174 DeviceId deviceId = event.subject().location().deviceId();
175 PortNumber port = event.subject().location().port();
176 Set<IpAddress> ips = event.subject().ipAddresses();
177 log.debug("Host {}/{} is removed from {}:{}", mac, vlanId, deviceId, port);
178
179 if (!srManager.deviceConfiguration.suppressHost()
180 .contains(new ConnectPoint(deviceId, port))) {
181 // Revoke bridging table entry
182 ForwardingObjective.Builder fob =
183 getForwardingObjectiveBuilder(deviceId, mac, vlanId, port);
184 ObjectiveContext context = new DefaultObjectiveContext(
185 (objective) -> log.debug("Host rule for {} revoked", event.subject()),
186 (objective, error) ->
187 log.warn("Failed to revoke host rule for {}: {}", event.subject(), error));
188 flowObjectiveService.forward(deviceId, fob.remove(context));
189
190 // Revoke IP table entry
191 ips.forEach(ip -> {
192 if (ip.isIp4()) {
193 srManager.routingRulePopulator.revokeIpRuleForHost(
194 deviceId, ip.getIp4Address(), mac, port);
195 }
196 });
197 }
198 }
199
200 protected void processHostMovedEvent(HostEvent event) {
201 MacAddress mac = event.subject().mac();
202 VlanId vlanId = event.subject().vlan();
203 DeviceId prevDeviceId = event.prevSubject().location().deviceId();
204 PortNumber prevPort = event.prevSubject().location().port();
205 Set<IpAddress> prevIps = event.prevSubject().ipAddresses();
206 DeviceId newDeviceId = event.subject().location().deviceId();
207 PortNumber newPort = event.subject().location().port();
208 Set<IpAddress> newIps = event.subject().ipAddresses();
209 log.debug("Host {}/{} is moved from {}:{} to {}:{}",
210 mac, vlanId, prevDeviceId, prevPort, newDeviceId, newPort);
211
212 if (!srManager.deviceConfiguration.suppressHost()
213 .contains(new ConnectPoint(prevDeviceId, prevPort))) {
214 // Revoke previous bridging table entry
215 ForwardingObjective.Builder prevFob =
216 getForwardingObjectiveBuilder(prevDeviceId, mac, vlanId, prevPort);
217 ObjectiveContext context = new DefaultObjectiveContext(
218 (objective) -> log.debug("Host rule for {} revoked", event.subject()),
219 (objective, error) ->
220 log.warn("Failed to revoke host rule for {}: {}", event.subject(), error));
221 flowObjectiveService.forward(prevDeviceId, prevFob.remove(context));
222
223 // Revoke previous IP table entry
224 prevIps.forEach(ip -> {
225 if (ip.isIp4()) {
226 srManager.routingRulePopulator.revokeIpRuleForHost(
227 prevDeviceId, ip.getIp4Address(), mac, prevPort);
228 }
229 });
230 }
231
232 if (!srManager.deviceConfiguration.suppressHost()
233 .contains(new ConnectPoint(newDeviceId, newPort))) {
234 // Populate new bridging table entry
235 ForwardingObjective.Builder newFob =
236 getForwardingObjectiveBuilder(newDeviceId, mac, vlanId, newPort);
237 ObjectiveContext context = new DefaultObjectiveContext(
238 (objective) -> log.debug("Host rule for {} populated", event.subject()),
239 (objective, error) ->
240 log.warn("Failed to populate host rule for {}: {}", event.subject(), error));
241 flowObjectiveService.forward(newDeviceId, newFob.add(context));
242
243 // Populate new IP table entry
244 newIps.forEach(ip -> {
245 if (ip.isIp4()) {
246 srManager.routingRulePopulator.populateIpRuleForHost(
247 newDeviceId, ip.getIp4Address(), mac, newPort);
248 }
249 });
250 }
251 }
252
253 protected void processHostUpdatedEvent(HostEvent event) {
254 MacAddress mac = event.subject().mac();
255 VlanId vlanId = event.subject().vlan();
256 DeviceId prevDeviceId = event.prevSubject().location().deviceId();
257 PortNumber prevPort = event.prevSubject().location().port();
258 Set<IpAddress> prevIps = event.prevSubject().ipAddresses();
259 DeviceId newDeviceId = event.subject().location().deviceId();
260 PortNumber newPort = event.subject().location().port();
261 Set<IpAddress> newIps = event.subject().ipAddresses();
262 log.debug("Host {}/{} is updated", mac, vlanId);
263
264 if (!srManager.deviceConfiguration.suppressHost()
265 .contains(new ConnectPoint(prevDeviceId, prevPort))) {
266 // Revoke previous IP table entry
267 prevIps.forEach(ip -> {
268 if (ip.isIp4()) {
269 srManager.routingRulePopulator.revokeIpRuleForHost(
270 prevDeviceId, ip.getIp4Address(), mac, prevPort);
271 }
272 });
273 }
274
275 if (!srManager.deviceConfiguration.suppressHost()
276 .contains(new ConnectPoint(newDeviceId, newPort))) {
277 // Populate new IP table entry
278 newIps.forEach(ip -> {
279 if (ip.isIp4()) {
280 srManager.routingRulePopulator.populateIpRuleForHost(
281 newDeviceId, ip.getIp4Address(), mac, newPort);
282 }
283 });
284 }
285 }
286}