blob: 1ae02c2176cf498aa89593748d613057c2fc4d4a [file] [log] [blame]
Jonathan Harta9e29552016-09-09 07:17:41 -07001/*
Brian O'Connora09fe5b2017-08-03 21:12:30 -07002 * Copyright 2017-present Open Networking Foundation
Jonathan Harta9e29552016-09-09 07:17:41 -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 */
16
17package org.onosproject.routing.impl;
18
Ray Milkeyd84f89b2018-08-17 14:54:17 -070019import org.osgi.service.component.annotations.Activate;
20import org.osgi.service.component.annotations.Component;
21import org.osgi.service.component.annotations.Deactivate;
22import org.osgi.service.component.annotations.Reference;
23import org.osgi.service.component.annotations.ReferenceCardinality;
Luca Pretee4a5e1a2016-09-07 17:01:22 -070024import org.onlab.packet.Ethernet;
25import org.onlab.packet.VlanId;
Jonathan Harta9e29552016-09-09 07:17:41 -070026import org.onosproject.core.ApplicationId;
27import org.onosproject.core.CoreService;
Ray Milkeyfacf2862017-08-03 11:58:29 -070028import org.onosproject.net.intf.Interface;
29import org.onosproject.net.intf.InterfaceEvent;
30import org.onosproject.net.intf.InterfaceListener;
31import org.onosproject.net.intf.InterfaceService;
Ray Milkeyb65d7842017-08-03 16:28:24 -070032import org.onosproject.net.neighbour.NeighbourMessageContext;
33import org.onosproject.net.neighbour.NeighbourMessageHandler;
34import org.onosproject.net.neighbour.NeighbourResolutionService;
Jonathan Harta9e29552016-09-09 07:17:41 -070035import org.onosproject.net.ConnectPoint;
36import org.onosproject.net.Host;
37import org.onosproject.net.config.NetworkConfigEvent;
38import org.onosproject.net.config.NetworkConfigListener;
39import org.onosproject.net.config.NetworkConfigService;
40import org.onosproject.net.host.HostService;
41import org.onosproject.routing.RoutingService;
42import org.onosproject.routing.config.BgpConfig;
43
44import java.util.HashSet;
45import java.util.Set;
46
Jonathan Harta9e29552016-09-09 07:17:41 -070047/**
48 * Manages neighbour message handlers for the use case of internal BGP speakers
49 * connected to the network at some point that are exchanging neighbour
50 * resolution messages with external routers that are connected behind interfaces.
51 * <p>
52 * For each internal speaker port we use a handler that proxies packets from
53 * that port to the appropriate external-facing interface port.
54 * For each external interface, we use a handler that responds to requests based
55 * on the interface configuration and proxies replies back the the internal BGP
56 * speaker.
57 * </p>
58 */
59@Component(immediate = true, enabled = false)
60public class BgpSpeakerNeighbourHandler {
61
Ray Milkeyd84f89b2018-08-17 14:54:17 -070062 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Jonathan Harta9e29552016-09-09 07:17:41 -070063 protected CoreService coreService;
64
Ray Milkeyd84f89b2018-08-17 14:54:17 -070065 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Jonathan Harta9e29552016-09-09 07:17:41 -070066 protected NetworkConfigService configService;
67
Ray Milkeyd84f89b2018-08-17 14:54:17 -070068 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Jonathan Harta9e29552016-09-09 07:17:41 -070069 protected InterfaceService interfaceService;
70
Ray Milkeyd84f89b2018-08-17 14:54:17 -070071 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Jonathan Harta9e29552016-09-09 07:17:41 -070072 protected NeighbourResolutionService neighbourService;
73
74 private ApplicationId appId;
75
76 private Set<ConnectPoint> speakerConnectPoints = new HashSet<>();
77
78
79 private InternalNetworkConfigListener configListener = new InternalNetworkConfigListener();
80 private InternalInterfaceListener interfaceListener = new InternalInterfaceListener();
81
82 private ExternalInterfaceNeighbourHandler externalHandler = new ExternalInterfaceNeighbourHandler();
83 private InternalSpeakerNeighbourHandler internalHandler = new InternalSpeakerNeighbourHandler();
84
85 @Activate
86 protected void activate() {
87 appId = coreService.registerApplication(RoutingService.ROUTER_APP_ID);
88 configService.addListener(configListener);
89 interfaceService.addListener(interfaceListener);
90
91 interfaceService.getInterfaces().forEach(
92 intf -> neighbourService.registerNeighbourHandler(intf, externalHandler, appId));
93 configureSpeakerHandlers();
94 }
95
96 @Deactivate
97 protected void deactivate() {
98 configService.removeListener(configListener);
99 interfaceService.removeListener(interfaceListener);
100
101 neighbourService.unregisterNeighbourHandlers(appId);
102 }
103
104 private void configureSpeakerHandlers() {
105 BgpConfig config = configService.getConfig(appId, RoutingService.CONFIG_CLASS);
106
107 if (config == null) {
108 return;
109 }
110
111 speakerConnectPoints.forEach(
112 cp -> neighbourService.unregisterNeighbourHandler(cp, internalHandler, appId));
113 speakerConnectPoints.clear();
114
115 config.bgpSpeakers().forEach(speaker -> {
116 neighbourService.registerNeighbourHandler(speaker.connectPoint(), internalHandler, appId);
117 speakerConnectPoints.add(speaker.connectPoint());
118 });
119 }
120
121 private void updateInterface(Interface intf) {
122 // Only use interfaces that have an IP address
Ray Milkey048bf9a2017-05-12 14:31:50 -0700123 if (!intf.ipAddressesList().isEmpty()) {
Jonathan Harta9e29552016-09-09 07:17:41 -0700124 neighbourService.registerNeighbourHandler(intf, externalHandler, appId);
125 }
126 }
127
128 private void removeInterface(Interface intf) {
129 neighbourService.unregisterNeighbourHandler(intf, externalHandler, appId);
130 }
131
132 /**
133 * Neighbour message handler for external facing ports that have interface
134 * configuration.
135 */
136 public class ExternalInterfaceNeighbourHandler implements
137 NeighbourMessageHandler {
138
139 @Override
140 public void handleMessage(NeighbourMessageContext context, HostService hostService) {
141 switch (context.type()) {
142 case REQUEST:
143 // Reply to requests that target our configured interface IP
144 // address on this port. Drop all other requests.
Jonathan Harta9e29552016-09-09 07:17:41 -0700145 interfaceService.getInterfacesByPort(context.inPort())
146 .stream()
Ray Milkey048bf9a2017-05-12 14:31:50 -0700147 .filter(intf -> intf.ipAddressesList()
Jonathan Harta9e29552016-09-09 07:17:41 -0700148 .stream()
Jonathan Hart1e393bb2016-09-14 08:51:09 -0700149 .anyMatch(ia -> ia.ipAddress().equals(context.target()) &&
150 ia.subnetAddress().contains(context.sender())))
Jonathan Harta9e29552016-09-09 07:17:41 -0700151 .forEach(intf -> context.reply(intf.mac()));
152
153 break;
154 case REPLY:
155 // Proxy replies over to our internal BGP speaker if the host
156 // is known to us
Jonathan Harte5387112017-02-02 13:22:31 -0800157 Set<Host> hosts = hostService.getHostsByMac(context.dstMac());
158
159 if (hosts.isEmpty()) {
Jonathan Harta9e29552016-09-09 07:17:41 -0700160 context.drop();
161 } else {
Jonathan Harte5387112017-02-02 13:22:31 -0800162 Host h = hosts.stream().findFirst().get();
Luca Pretee4a5e1a2016-09-07 17:01:22 -0700163 VlanId bgpSpeakerVlanId = h.vlan();
Jonathan Harte5387112017-02-02 13:22:31 -0800164
Luca Pretee4a5e1a2016-09-07 17:01:22 -0700165 if (!bgpSpeakerVlanId.equals(VlanId.NONE)) {
166 context.packet().setVlanID(bgpSpeakerVlanId.toShort());
167 } else {
168 context.packet().setVlanID(Ethernet.VLAN_UNTAGGED);
169 }
Jonathan Hart2efe0c22016-09-21 12:04:45 -0700170 context.forward(h.location());
Jonathan Harta9e29552016-09-09 07:17:41 -0700171 }
172 break;
173 default:
174 break;
175 }
176 }
177
178 }
179
180 /**
181 * Neighbour message handler for ports connected to the internal BGP speakers.
182 */
183 private class InternalSpeakerNeighbourHandler implements
184 NeighbourMessageHandler {
185 @Override
186 public void handleMessage(NeighbourMessageContext context, HostService hostService) {
187 // For messages coming from a BGP speaker, look at the sender address
188 // to find the interface to proxy to
189 interfaceService.getInterfacesByIp(context.sender())
Jonathan Hart2efe0c22016-09-21 12:04:45 -0700190 .forEach(context::forward);
Jonathan Harta9e29552016-09-09 07:17:41 -0700191 }
192 }
193
194 private class InternalNetworkConfigListener implements
195 NetworkConfigListener {
196
197 @Override
198 public void event(NetworkConfigEvent event) {
199 switch (event.type()) {
200 case CONFIG_REGISTERED:
201 break;
202 case CONFIG_UNREGISTERED:
203 break;
204 case CONFIG_ADDED:
205 case CONFIG_UPDATED:
206 case CONFIG_REMOVED:
207 if (event.configClass() == RoutingService.CONFIG_CLASS) {
208 configureSpeakerHandlers();
209 }
210 break;
211 default:
212 break;
213 }
214 }
215 }
216
217 private class InternalInterfaceListener implements InterfaceListener {
218
219 @Override
220 public void event(InterfaceEvent event) {
221 switch (event.type()) {
222 case INTERFACE_ADDED:
223 updateInterface(event.subject());
224 break;
225 case INTERFACE_UPDATED:
226 break;
227 case INTERFACE_REMOVED:
228 removeInterface(event.subject());
229 break;
230 default:
231 break;
232 }
233 }
234 }
235}