blob: 5602d0f0c1ca4f9be6173db154f3887d2d94f3cb [file] [log] [blame]
Jonathan Hartf5829202015-02-12 09:37:02 -08001/*
Brian O'Connora09fe5b2017-08-03 21:12:30 -07002 * Copyright 2015-present Open Networking Foundation
Jonathan Hartf5829202015-02-12 09:37:02 -08003 *
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 */
16package org.onosproject.bgprouter;
17
18import org.onlab.packet.Ethernet;
19import org.onlab.packet.IPv4;
20import org.onlab.packet.IpAddress;
21import org.onlab.packet.TCP;
Hyunsun Mooncf732fb2015-08-22 21:04:23 -070022import org.onlab.packet.TpPort;
Jonathan Hartf5829202015-02-12 09:37:02 -080023import org.onosproject.core.ApplicationId;
Ray Milkeyfacf2862017-08-03 11:58:29 -070024import org.onosproject.net.intf.Interface;
25import org.onosproject.net.intf.InterfaceService;
Jonathan Hartf5829202015-02-12 09:37:02 -080026import org.onosproject.net.ConnectPoint;
Jonathan Hart936a7292015-03-06 18:02:57 -080027import org.onosproject.net.flow.DefaultTrafficSelector;
Jonathan Hartf5829202015-02-12 09:37:02 -080028import org.onosproject.net.flow.DefaultTrafficTreatment;
Jonathan Hart936a7292015-03-06 18:02:57 -080029import org.onosproject.net.flow.TrafficSelector;
Jonathan Hartf5829202015-02-12 09:37:02 -080030import org.onosproject.net.flow.TrafficTreatment;
Saurav Das3d038262015-04-23 12:36:58 -070031import org.onosproject.net.flowobjective.DefaultForwardingObjective;
32import org.onosproject.net.flowobjective.FlowObjectiveService;
33import org.onosproject.net.flowobjective.ForwardingObjective;
Jonathan Hartf5829202015-02-12 09:37:02 -080034import org.onosproject.net.packet.DefaultOutboundPacket;
35import org.onosproject.net.packet.OutboundPacket;
36import org.onosproject.net.packet.PacketContext;
Jonathan Hartf5829202015-02-12 09:37:02 -080037import org.onosproject.net.packet.PacketProcessor;
38import org.onosproject.net.packet.PacketService;
Jonathan Hart4cb39882015-08-12 23:50:55 -040039import org.onosproject.routing.config.BgpConfig;
Saurav Das3d038262015-04-23 12:36:58 -070040import org.slf4j.Logger;
Jonathan Hartf5829202015-02-12 09:37:02 -080041
Jonathan Hart4cb39882015-08-12 23:50:55 -040042import java.util.Optional;
43import java.util.Set;
44
45import static org.slf4j.LoggerFactory.getLogger;
46
Jonathan Hartf5829202015-02-12 09:37:02 -080047
48/**
49 * Manages connectivity between peers by tunnelling BGP traffic through
50 * OpenFlow packet-ins and packet-outs.
51 */
52public class TunnellingConnectivityManager {
53
54 private static final short BGP_PORT = 179;
Saurav Das3d038262015-04-23 12:36:58 -070055 private final Logger log = getLogger(getClass());
Jonathan Hartf5829202015-02-12 09:37:02 -080056 private final ApplicationId appId;
57
Jonathan Hart4cb39882015-08-12 23:50:55 -040058 private final BgpConfig.BgpSpeakerConfig bgpSpeaker;
Jonathan Hart936a7292015-03-06 18:02:57 -080059
Jonathan Hartf5829202015-02-12 09:37:02 -080060 private final PacketService packetService;
Jonathan Hart4cb39882015-08-12 23:50:55 -040061 private final InterfaceService interfaceService;
Saurav Das3d038262015-04-23 12:36:58 -070062 private final FlowObjectiveService flowObjectiveService;
Jonathan Hartf5829202015-02-12 09:37:02 -080063
64 private final BgpProcessor processor = new BgpProcessor();
65
66 public TunnellingConnectivityManager(ApplicationId appId,
Jonathan Hart4cb39882015-08-12 23:50:55 -040067 BgpConfig bgpConfig,
68 InterfaceService interfaceService,
Jonathan Hart936a7292015-03-06 18:02:57 -080069 PacketService packetService,
Saurav Das3d038262015-04-23 12:36:58 -070070 FlowObjectiveService flowObjectiveService) {
Jonathan Hartf5829202015-02-12 09:37:02 -080071 this.appId = appId;
Jonathan Hart4cb39882015-08-12 23:50:55 -040072 this.interfaceService = interfaceService;
Jonathan Hartf5829202015-02-12 09:37:02 -080073 this.packetService = packetService;
Saurav Das3d038262015-04-23 12:36:58 -070074 this.flowObjectiveService = flowObjectiveService;
Jonathan Hart936a7292015-03-06 18:02:57 -080075
Jonathan Hart4cb39882015-08-12 23:50:55 -040076 Optional<BgpConfig.BgpSpeakerConfig> bgpSpeaker =
77 bgpConfig.bgpSpeakers().stream().findAny();
Jonathan Hart936a7292015-03-06 18:02:57 -080078
Jonathan Hart4cb39882015-08-12 23:50:55 -040079 if (!bgpSpeaker.isPresent()) {
Jonathan Hart936a7292015-03-06 18:02:57 -080080 throw new IllegalArgumentException("Must have at least one BGP speaker configured");
81 }
82
Jonathan Hart4cb39882015-08-12 23:50:55 -040083 this.bgpSpeaker = bgpSpeaker.get();
Jonathan Hart936a7292015-03-06 18:02:57 -080084
sanghof22fb402015-04-27 23:55:10 -070085 }
86
87 public void start() {
Brian O'Connor3b783262015-07-29 17:49:24 -070088 packetService.addProcessor(processor, PacketProcessor.director(3));
sanghof22fb402015-04-27 23:55:10 -070089 }
90
91 public void stop() {
92 packetService.removeProcessor(processor);
93 // Should revoke packet requests in the future
94 }
95
96 /**
97 * Pushes the flow rules for forwarding BGP TCP packets to controller.
98 * It is called when switches are connected and available.
99 */
100 public void notifySwitchAvailable() {
101 // control plane OVS is available, push default flows
Jonathan Hart936a7292015-03-06 18:02:57 -0800102 TrafficSelector selectorDst = DefaultTrafficSelector.builder()
103 .matchEthType(Ethernet.TYPE_IPV4)
104 .matchIPProtocol(IPv4.PROTOCOL_TCP)
Hyunsun Mooncf732fb2015-08-22 21:04:23 -0700105 .matchTcpDst(TpPort.tpPort(BGP_PORT))
Jonathan Hart936a7292015-03-06 18:02:57 -0800106 .build();
107
108 TrafficSelector selectorSrc = DefaultTrafficSelector.builder()
109 .matchEthType(Ethernet.TYPE_IPV4)
110 .matchIPProtocol(IPv4.PROTOCOL_TCP)
Hyunsun Mooncf732fb2015-08-22 21:04:23 -0700111 .matchTcpSrc(TpPort.tpPort(BGP_PORT))
Jonathan Hart936a7292015-03-06 18:02:57 -0800112 .build();
113
114 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
115 .punt()
116 .build();
117
Saurav Das3d038262015-04-23 12:36:58 -0700118 ForwardingObjective puntSrc = DefaultForwardingObjective.builder()
119 .fromApp(appId)
120 .makePermanent()
121 .withSelector(selectorSrc)
122 .withTreatment(treatment)
123 .withFlag(ForwardingObjective.Flag.VERSATILE)
124 .add();
125 flowObjectiveService.forward(bgpSpeaker.connectPoint().deviceId(),
sanghof22fb402015-04-27 23:55:10 -0700126 puntSrc);
Saurav Das3d038262015-04-23 12:36:58 -0700127
128 ForwardingObjective puntDst = DefaultForwardingObjective.builder()
129 .fromApp(appId)
130 .makePermanent()
131 .withSelector(selectorDst)
132 .withTreatment(treatment)
133 .withFlag(ForwardingObjective.Flag.VERSATILE)
134 .add();
135 flowObjectiveService.forward(bgpSpeaker.connectPoint().deviceId(),
sanghof22fb402015-04-27 23:55:10 -0700136 puntDst);
Saurav Das3d038262015-04-23 12:36:58 -0700137 log.info("Sent punt forwarding objective to {}", bgpSpeaker.connectPoint().deviceId());
Jonathan Hartf5829202015-02-12 09:37:02 -0800138 }
139
140 /**
141 * Forwards a BGP packet to another connect point.
142 *
143 * @param context the packet context of the incoming packet
144 */
145 private void forward(PacketContext context) {
Jonathan Hartf5829202015-02-12 09:37:02 -0800146 ConnectPoint outputPort = null;
Jonathan Hartf5829202015-02-12 09:37:02 -0800147
148 IPv4 ipv4 = (IPv4) context.inPacket().parsed().getPayload();
149 IpAddress dstAddress = IpAddress.valueOf(ipv4.getDestinationAddress());
150
Jonathan Hart936a7292015-03-06 18:02:57 -0800151 if (context.inPacket().receivedFrom().equals(bgpSpeaker.connectPoint())) {
Jonathan Hart4cb39882015-08-12 23:50:55 -0400152 if (bgpSpeaker.peers().contains(dstAddress)) {
153 Interface intf = interfaceService.getMatchingInterface(dstAddress);
154 if (intf != null) {
155 outputPort = intf.connectPoint();
156 }
Jonathan Hartf5829202015-02-12 09:37:02 -0800157 }
Jonathan Hart4cb39882015-08-12 23:50:55 -0400158 } else {
159 Set<Interface> interfaces =
160 interfaceService.getInterfacesByPort(context.inPacket().receivedFrom());
161
162 if (interfaces.stream()
Ray Milkey048bf9a2017-05-12 14:31:50 -0700163 .flatMap(intf -> intf.ipAddressesList().stream())
Jonathan Hart4cb39882015-08-12 23:50:55 -0400164 .anyMatch(ia -> ia.ipAddress().equals(dstAddress))) {
Jonathan Hart936a7292015-03-06 18:02:57 -0800165 outputPort = bgpSpeaker.connectPoint();
Jonathan Hartf5829202015-02-12 09:37:02 -0800166 }
167 }
168
169 if (outputPort != null) {
170 TrafficTreatment t = DefaultTrafficTreatment.builder()
171 .setOutput(outputPort.port()).build();
172 OutboundPacket o = new DefaultOutboundPacket(
173 outputPort.deviceId(), t, context.inPacket().unparsed());
174 packetService.emit(o);
175 }
176 }
177
178 /**
179 * Packet processor responsible receiving and filtering BGP packets.
180 */
181 private class BgpProcessor implements PacketProcessor {
182
183 @Override
184 public void process(PacketContext context) {
185 // Stop processing if the packet has been handled, since we
186 // can't do any more to it.
187 if (context.isHandled()) {
188 return;
189 }
190
191 Ethernet packet = context.inPacket().parsed();
192
193 if (packet == null) {
194 return;
195 }
196
197 if (packet.getEtherType() == Ethernet.TYPE_IPV4) {
198 IPv4 ipv4Packet = (IPv4) packet.getPayload();
199 if (ipv4Packet.getProtocol() == IPv4.PROTOCOL_TCP) {
200 TCP tcpPacket = (TCP) ipv4Packet.getPayload();
201
202 if (tcpPacket.getDestinationPort() == BGP_PORT ||
203 tcpPacket.getSourcePort() == BGP_PORT) {
204 forward(context);
205 }
206 }
207 }
208 }
209 }
210}