Jonathan Hart

Implemented SDN-IP/BgpRouter neighbour handling using NeighbourResolutionService

Change-Id: Ia7e3f18bd69d56cb2f46f815eaa2352533a54ed0
...@@ -19,6 +19,5 @@ onos_app ( ...@@ -19,6 +19,5 @@ onos_app (
19 category = 'Traffic Steering', 19 category = 'Traffic Steering',
20 url = 'http://onosproject.org', 20 url = 'http://onosproject.org',
21 description = 'BGP router application.', 21 description = 'BGP router application.',
22 - required_apps = [ 'org.onosproject.proxyarp' ],
23 included_bundles = BUNDLES, 22 included_bundles = BUNDLES,
24 ) 23 )
......
...@@ -22,5 +22,4 @@ ...@@ -22,5 +22,4 @@
22 <artifact>mvn:${project.groupId}/${project.artifactId}/${project.version}</artifact> 22 <artifact>mvn:${project.groupId}/${project.artifactId}/${project.version}</artifact>
23 <artifact>mvn:${project.groupId}/onos-app-routing-api/${project.version}</artifact> 23 <artifact>mvn:${project.groupId}/onos-app-routing-api/${project.version}</artifact>
24 <artifact>mvn:${project.groupId}/onos-app-routing/${project.version}</artifact> 24 <artifact>mvn:${project.groupId}/onos-app-routing/${project.version}</artifact>
25 - <artifact>mvn:${project.groupId}/onos-app-proxyarp/${project.version}</artifact>
26 </app> 25 </app>
......
...@@ -95,6 +95,7 @@ public class BgpRouter { ...@@ -95,6 +95,7 @@ public class BgpRouter {
95 static { 95 static {
96 components.add("org.onosproject.routing.bgp.BgpSessionManager"); 96 components.add("org.onosproject.routing.bgp.BgpSessionManager");
97 components.add("org.onosproject.routing.impl.Router"); 97 components.add("org.onosproject.routing.impl.Router");
98 + components.add("org.onosproject.routing.impl.BgpSpeakerNeighbourHandler");
98 components.add("org.onosproject.routing.impl.SingleSwitchFibInstaller"); 99 components.add("org.onosproject.routing.impl.SingleSwitchFibInstaller");
99 } 100 }
100 101
......
1 +/*
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 +
17 +package org.onosproject.routing.impl;
18 +
19 +import org.apache.felix.scr.annotations.Activate;
20 +import org.apache.felix.scr.annotations.Component;
21 +import org.apache.felix.scr.annotations.Deactivate;
22 +import org.apache.felix.scr.annotations.Reference;
23 +import org.apache.felix.scr.annotations.ReferenceCardinality;
24 +import org.onosproject.core.ApplicationId;
25 +import org.onosproject.core.CoreService;
26 +import org.onosproject.incubator.net.intf.Interface;
27 +import org.onosproject.incubator.net.intf.InterfaceEvent;
28 +import org.onosproject.incubator.net.intf.InterfaceListener;
29 +import org.onosproject.incubator.net.intf.InterfaceService;
30 +import org.onosproject.incubator.net.neighbour.NeighbourMessageContext;
31 +import org.onosproject.incubator.net.neighbour.NeighbourMessageHandler;
32 +import org.onosproject.incubator.net.neighbour.NeighbourResolutionService;
33 +import org.onosproject.net.ConnectPoint;
34 +import org.onosproject.net.Host;
35 +import org.onosproject.net.config.NetworkConfigEvent;
36 +import org.onosproject.net.config.NetworkConfigListener;
37 +import org.onosproject.net.config.NetworkConfigService;
38 +import org.onosproject.net.host.HostService;
39 +import org.onosproject.routing.RoutingService;
40 +import org.onosproject.routing.config.BgpConfig;
41 +
42 +import java.util.HashSet;
43 +import java.util.Set;
44 +
45 +import static org.onosproject.net.HostId.hostId;
46 +
47 +/**
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)
60 +public class BgpSpeakerNeighbourHandler {
61 +
62 + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
63 + protected CoreService coreService;
64 +
65 + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
66 + protected NetworkConfigService configService;
67 +
68 + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
69 + protected InterfaceService interfaceService;
70 +
71 + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
72 + 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
123 + if (!intf.ipAddresses().isEmpty()) {
124 + 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.
145 +
146 + interfaceService.getInterfacesByPort(context.inPort())
147 + .stream()
148 + .filter(intf -> intf.ipAddresses()
149 + .stream()
150 + .anyMatch(ia -> ia.ipAddress().equals(context.target())))
151 + .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
157 + Host h = hostService.getHost(hostId(context.dstMac(), context.vlan()));
158 +
159 + if (h == null) {
160 + context.drop();
161 + } else {
162 + context.proxy(h.location());
163 + }
164 + break;
165 + default:
166 + break;
167 + }
168 + }
169 +
170 + }
171 +
172 + /**
173 + * Neighbour message handler for ports connected to the internal BGP speakers.
174 + */
175 + private class InternalSpeakerNeighbourHandler implements
176 + NeighbourMessageHandler {
177 + @Override
178 + public void handleMessage(NeighbourMessageContext context, HostService hostService) {
179 + // For messages coming from a BGP speaker, look at the sender address
180 + // to find the interface to proxy to
181 + interfaceService.getInterfacesByIp(context.sender())
182 + .stream()
183 + .filter(intf -> intf.vlan().equals(context.vlan()))
184 + .map(intf -> intf.connectPoint())
185 + .forEach(context::proxy);
186 + }
187 + }
188 +
189 + private class InternalNetworkConfigListener implements
190 + NetworkConfigListener {
191 +
192 + @Override
193 + public void event(NetworkConfigEvent event) {
194 + switch (event.type()) {
195 + case CONFIG_REGISTERED:
196 + break;
197 + case CONFIG_UNREGISTERED:
198 + break;
199 + case CONFIG_ADDED:
200 + case CONFIG_UPDATED:
201 + case CONFIG_REMOVED:
202 + if (event.configClass() == RoutingService.CONFIG_CLASS) {
203 + configureSpeakerHandlers();
204 + }
205 + break;
206 + default:
207 + break;
208 + }
209 + }
210 + }
211 +
212 + private class InternalInterfaceListener implements InterfaceListener {
213 +
214 + @Override
215 + public void event(InterfaceEvent event) {
216 + switch (event.type()) {
217 + case INTERFACE_ADDED:
218 + updateInterface(event.subject());
219 + break;
220 + case INTERFACE_UPDATED:
221 + break;
222 + case INTERFACE_REMOVED:
223 + removeInterface(event.subject());
224 + break;
225 + default:
226 + break;
227 + }
228 + }
229 + }
230 +}
...@@ -26,6 +26,5 @@ onos_app ( ...@@ -26,6 +26,5 @@ onos_app (
26 category = 'Utility', 26 category = 'Utility',
27 url = 'http://onosproject.org', 27 url = 'http://onosproject.org',
28 included_bundles = BUNDLES, 28 included_bundles = BUNDLES,
29 - required_apps = [ 'org.onosproject.proxyarp' ],
30 description = 'SDN-IP peering application', 29 description = 'SDN-IP peering application',
31 ) 30 )
......
...@@ -17,7 +17,7 @@ ...@@ -17,7 +17,7 @@
17 <app name="org.onosproject.sdnip" origin="ON.Lab" version="${project.version}" 17 <app name="org.onosproject.sdnip" origin="ON.Lab" version="${project.version}"
18 category="Traffic Steering" url="http://onosproject.org" title="SDN-IP App" 18 category="Traffic Steering" url="http://onosproject.org" title="SDN-IP App"
19 featuresRepo="mvn:${project.groupId}/${project.artifactId}/${project.version}/xml/features" 19 featuresRepo="mvn:${project.groupId}/${project.artifactId}/${project.version}/xml/features"
20 - features="${project.artifactId}" apps="org.onosproject.proxyarp"> 20 + features="${project.artifactId}">
21 <description>${project.description}</description> 21 <description>${project.description}</description>
22 <artifact>mvn:${project.groupId}/${project.artifactId}/${project.version}</artifact> 22 <artifact>mvn:${project.groupId}/${project.artifactId}/${project.version}</artifact>
23 <artifact>mvn:${project.groupId}/onos-app-routing-api/${project.version}</artifact> 23 <artifact>mvn:${project.groupId}/onos-app-routing-api/${project.version}</artifact>
......
...@@ -68,6 +68,7 @@ public class SdnIp { ...@@ -68,6 +68,7 @@ public class SdnIp {
68 68
69 private final List<String> components = ImmutableList.of( 69 private final List<String> components = ImmutableList.of(
70 "org.onosproject.routing.bgp.BgpSessionManager", 70 "org.onosproject.routing.bgp.BgpSessionManager",
71 + "org.onosproject.routing.impl.BgpSpeakerNeighbourHandler",
71 org.onosproject.sdnip.SdnIpFib.class.getName() 72 org.onosproject.sdnip.SdnIpFib.class.getName()
72 ); 73 );
73 74
......