blob: 22389c31cca2b58cb274d650f240cd3c90b51587 [file] [log] [blame]
Jonathan Hartf5829202015-02-12 09:37:02 -08001/*
2 * Copyright 2015 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 */
16package org.onosproject.bgprouter;
17
18import com.google.common.collect.ConcurrentHashMultiset;
19import com.google.common.collect.Multiset;
20import org.apache.felix.scr.annotations.Activate;
21import org.apache.felix.scr.annotations.Component;
22import org.apache.felix.scr.annotations.Deactivate;
23import org.apache.felix.scr.annotations.Reference;
24import org.apache.felix.scr.annotations.ReferenceCardinality;
25import org.onlab.packet.Ethernet;
26import org.onosproject.core.ApplicationId;
27import org.onosproject.core.CoreService;
28import org.onosproject.net.DeviceId;
29import org.onosproject.net.flow.DefaultFlowRule;
30import org.onosproject.net.flow.DefaultTrafficSelector;
31import org.onosproject.net.flow.DefaultTrafficTreatment;
32import org.onosproject.net.flow.FlowRule;
33import org.onosproject.net.flow.FlowRuleService;
34import org.onosproject.net.flow.TrafficSelector;
35import org.onosproject.net.flow.TrafficTreatment;
36import org.onosproject.net.group.DefaultGroupBucket;
37import org.onosproject.net.group.DefaultGroupDescription;
38import org.onosproject.net.group.Group;
39import org.onosproject.net.group.GroupBucket;
40import org.onosproject.net.group.GroupBuckets;
41import org.onosproject.net.group.GroupDescription;
42import org.onosproject.net.group.GroupKey;
43import org.onosproject.net.group.GroupService;
44import org.onosproject.net.packet.PacketService;
45import org.onosproject.routingapi.FibListener;
46import org.onosproject.routingapi.FibUpdate;
47import org.onosproject.routingapi.RoutingService;
48import org.onosproject.routingapi.config.Interface;
49import org.onosproject.routingapi.config.RoutingConfigurationService;
50import org.slf4j.Logger;
51import org.slf4j.LoggerFactory;
52
53import java.util.Collection;
54import java.util.Collections;
55import java.util.HashMap;
56import java.util.Map;
57
58/**
59 * BgpRouter component.
60 */
61@Component(immediate = true)
62public class BgpRouter {
63
64 private static final Logger log = LoggerFactory.getLogger(BgpRouter.class);
65
66 private static final String BGP_ROUTER_APP = "org.onosproject.bgprouter";
67
68 private static final int PRIORITY = 1;
69
70 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
71 protected CoreService coreService;
72
73 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
74 protected FlowRuleService flowService;
75
76 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
77 protected GroupService groupService;
78
79 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
80 protected RoutingService routingService;
81
82 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
83 protected RoutingConfigurationService configService;
84
85 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
86 protected PacketService packetService;
87
88 private ApplicationId appId;
89
90 private final Multiset<NextHop> nextHops = ConcurrentHashMultiset.create();
91 private final Map<NextHop, NextHopGroupKey> groups = new HashMap<>();
92
93 private DeviceId deviceId = DeviceId.deviceId("of:00000000000000a1"); // TODO config
94
95 private TunnellingConnectivityManager connectivityManager;
96
97 @Activate
98 protected void activate() {
99 log.info("Bgp1Router started");
100 appId = coreService.registerApplication(BGP_ROUTER_APP);
101
102 connectivityManager = new TunnellingConnectivityManager(appId,
103 configService,
104 packetService);
105
106 routingService.start(new InternalFibListener());
107
108 connectivityManager.start();
109
110 log.info("BgpRouter started");
111 }
112
113 @Deactivate
114 protected void deactivate() {
115 routingService.stop();
116 connectivityManager.stop();
117
118 log.info("BgpRouter stopped");
119 }
120
121 private void updateFibEntry(Collection<FibUpdate> updates) {
122 for (FibUpdate update : updates) {
123 NextHop nextHop = new NextHop(update.entry().nextHopIp(),
124 update.entry().nextHopMac());
125
126 addNextHop(nextHop);
127
128 TrafficSelector selector = DefaultTrafficSelector.builder()
129 .matchEthType(Ethernet.TYPE_IPV4)
130 .matchIPDst(update.entry().prefix())
131 .build();
132
133 // TODO ensure group exists
134 NextHopGroupKey groupKey = groups.get(nextHop);
135 Group group = groupService.getGroup(deviceId, groupKey);
136 if (group == null) {
137 // TODO handle this
138 log.warn("oops, group {} wasn't there");
139 continue;
140 }
141
142 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
143 .group(group.id())
144 .build();
145
146 FlowRule flowRule = new DefaultFlowRule(deviceId, selector, treatment,
147 PRIORITY, appId, 0, true,
148 FlowRule.Type.IP);
149
150 flowService.applyFlowRules(flowRule);
151 }
152 }
153
154 private void deleteFibEntry(Collection<FibUpdate> withdraws) {
155 for (FibUpdate update : withdraws) {
156 NextHop nextHop = new NextHop(update.entry().nextHopIp(),
157 update.entry().nextHopMac());
158
159 deleteNextHop(nextHop);
160
161 TrafficSelector selector = DefaultTrafficSelector.builder()
162 .matchIPDst(update.entry().prefix())
163 .build();
164
165 FlowRule flowRule = new DefaultFlowRule(deviceId, selector, null,
166 PRIORITY, appId, 0, true,
167 FlowRule.Type.IP);
168
169 flowService.removeFlowRules(flowRule);
170 }
171 }
172
173 private void addNextHop(NextHop nextHop) {
174 if (nextHops.add(nextHop, 1) == 0) {
175 // There was no next hop in the multiset
176
177 Interface egressIntf = configService.getMatchingInterface(nextHop.ip());
178 if (egressIntf == null) {
179 log.warn("no egress interface found for {}", nextHop);
180 return;
181 }
182
183 NextHopGroupKey groupKey = new NextHopGroupKey(nextHop.ip());
184 groups.put(nextHop, groupKey);
185
186 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
187 .setEthSrc(egressIntf.mac())
188 .setEthDst(nextHop.mac())
189 .setVlanId(egressIntf.vlan())
190 .setOutput(egressIntf.connectPoint().port())
191 .build();
192
193 GroupBucket bucket = DefaultGroupBucket.createIndirectGroupBucket(treatment);
194
195 GroupDescription groupDescription
196 = new DefaultGroupDescription(deviceId,
197 GroupDescription.Type.INDIRECT,
198 new GroupBuckets(Collections
199 .singletonList(bucket)),
200 groupKey,
201 appId);
202
203 groupService.addGroup(groupDescription);
204 }
205 }
206
207 private void deleteNextHop(NextHop nextHop) {
208 if (nextHops.remove(nextHop, 1) <= 1) {
209 // There was one or less next hops, so there are now none
210
211 log.debug("removing group");
212
213 GroupKey groupKey = groups.remove(nextHop);
214 groupService.removeGroup(deviceId, groupKey, appId);
215 }
216 }
217
218 private class InternalFibListener implements FibListener {
219
220 @Override
221 public void update(Collection<FibUpdate> updates,
222 Collection<FibUpdate> withdraws) {
223 BgpRouter.this.deleteFibEntry(withdraws);
224 BgpRouter.this.updateFibEntry(updates);
225 }
226 }
227}