1+ /*
2+ * Copyright 2019-present Open Networking Foundation
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+ package org .onosproject .openstacknetworking .impl ;
17+
18+ import org .onlab .packet .Ethernet ;
19+ import org .onosproject .cluster .ClusterService ;
20+ import org .onosproject .cluster .LeadershipService ;
21+ import org .onosproject .core .ApplicationId ;
22+ import org .onosproject .core .CoreService ;
23+ import org .onosproject .mastership .MastershipService ;
24+ import org .onosproject .net .DeviceId ;
25+ import org .onosproject .net .Port ;
26+ import org .onosproject .net .PortNumber ;
27+ import org .onosproject .net .device .DeviceEvent ;
28+ import org .onosproject .net .device .DeviceListener ;
29+ import org .onosproject .net .device .DeviceService ;
30+ import org .onosproject .net .driver .DriverService ;
31+ import org .onosproject .net .flow .DefaultTrafficSelector ;
32+ import org .onosproject .net .flow .DefaultTrafficTreatment ;
33+ import org .onosproject .net .flow .TrafficSelector ;
34+ import org .onosproject .net .flow .TrafficTreatment ;
35+ import org .onosproject .openstacknetworking .api .OpenstackFlowRuleService ;
36+ import org .onosproject .openstacknode .api .OpenstackNode ;
37+ import org .onosproject .openstacknode .api .OpenstackNodeService ;
38+ import org .osgi .service .component .annotations .Activate ;
39+ import org .osgi .service .component .annotations .Component ;
40+ import org .osgi .service .component .annotations .Deactivate ;
41+ import org .osgi .service .component .annotations .Reference ;
42+ import org .osgi .service .component .annotations .ReferenceCardinality ;
43+ import org .slf4j .Logger ;
44+
45+ import java .util .Set ;
46+ import java .util .concurrent .ExecutorService ;
47+ import java .util .stream .Collectors ;
48+
49+ import static java .util .concurrent .Executors .newSingleThreadExecutor ;
50+ import static org .onlab .util .Tools .groupedThreads ;
51+ import static org .onosproject .net .AnnotationKeys .PORT_NAME ;
52+ import static org .onosproject .openstacknetworking .api .Constants .DHCP_TABLE ;
53+ import static org .onosproject .openstacknetworking .api .Constants .OPENSTACK_NETWORKING_APP_ID ;
54+ import static org .onosproject .openstacknetworking .api .Constants .PRIORITY_FLAT_JUMP_UPSTREAM_RULE ;
55+ import static org .onosproject .openstacknetworking .api .Constants .STAT_FLAT_OUTBOUND_TABLE ;
56+ import static org .onosproject .openstacknetworking .util .OpenstackNetworkingUtil .structurePortName ;
57+ import static org .onosproject .openstacknode .api .Constants .INTEGRATION_TO_PHYSICAL_PREFIX ;
58+ import static org .slf4j .LoggerFactory .getLogger ;
59+
60+ /**
61+ * Populates switching flow rules on OVS for the physical interfaces.
62+ */
63+ @ Component (immediate = true )
64+ public class OpenstackSwitchingPhysicalHandler {
65+
66+ private final Logger log = getLogger (getClass ());
67+
68+ @ Reference (cardinality = ReferenceCardinality .MANDATORY )
69+ protected CoreService coreService ;
70+
71+ @ Reference (cardinality = ReferenceCardinality .MANDATORY )
72+ protected MastershipService mastershipService ;
73+
74+ @ Reference (cardinality = ReferenceCardinality .MANDATORY )
75+ protected DeviceService deviceService ;
76+
77+ @ Reference (cardinality = ReferenceCardinality .MANDATORY )
78+ protected DriverService driverService ;
79+
80+ @ Reference (cardinality = ReferenceCardinality .MANDATORY )
81+ protected ClusterService clusterService ;
82+
83+ @ Reference (cardinality = ReferenceCardinality .MANDATORY )
84+ protected LeadershipService leadershipService ;
85+
86+ @ Reference (cardinality = ReferenceCardinality .MANDATORY )
87+ protected OpenstackFlowRuleService osFlowRuleService ;
88+
89+ @ Reference (cardinality = ReferenceCardinality .MANDATORY )
90+ protected OpenstackNodeService osNodeService ;
91+
92+ private final ExecutorService eventExecutor = newSingleThreadExecutor (
93+ groupedThreads (this .getClass ().getSimpleName (), "event-handler" ));
94+ private final InternalDeviceListener internalDeviceListener = new InternalDeviceListener ();
95+
96+ private ApplicationId appId ;
97+
98+ @ Activate
99+ protected void activate () {
100+ appId = coreService .registerApplication (OPENSTACK_NETWORKING_APP_ID );
101+ deviceService .addListener (internalDeviceListener );
102+
103+ log .info ("Started" );
104+ }
105+
106+ @ Deactivate
107+ protected void deactivate () {
108+ eventExecutor .shutdown ();
109+ deviceService .removeListener (internalDeviceListener );
110+
111+ log .info ("Stopped" );
112+ }
113+
114+ /**
115+ * An internal device listener which listens the port events generated from
116+ * OVS integration bridge.
117+ */
118+ private class InternalDeviceListener implements DeviceListener {
119+
120+ @ Override
121+ public boolean isRelevant (DeviceEvent event ) {
122+ Port port = event .port ();
123+ if (port == null ) {
124+ return false ;
125+ }
126+
127+ OpenstackNode osNode = osNodeService .node (event .subject ().id ());
128+ if (osNode == null ) {
129+ return false ;
130+ }
131+
132+ Set <String > intPatchPorts = osNode .phyIntfs ().stream ()
133+ .map (pi -> structurePortName (INTEGRATION_TO_PHYSICAL_PREFIX
134+ + pi .network ())).collect (Collectors .toSet ());
135+ String portName = port .annotations ().value (PORT_NAME );
136+
137+ return intPatchPorts .contains (portName );
138+ }
139+
140+ private boolean isRelevantHelper (DeviceEvent event ) {
141+ return mastershipService .isLocalMaster (event .subject ().id ());
142+ }
143+
144+ @ Override
145+ public void event (DeviceEvent event ) {
146+ log .info ("Device event occurred with type {}" , event .type ());
147+
148+ switch (event .type ()) {
149+ case PORT_ADDED :
150+ case PORT_UPDATED :
151+ eventExecutor .execute (() -> processPortAddition (event ));
152+ break ;
153+ case PORT_REMOVED :
154+ eventExecutor .execute (() -> processPortRemoval (event ));
155+ break ;
156+ default :
157+ break ;
158+ }
159+ }
160+
161+ private void processPortAddition (DeviceEvent event ) {
162+ if (!isRelevantHelper (event )) {
163+ return ;
164+ }
165+
166+ setFlatJumpRulesForPatchPort (event .subject ().id (),
167+ event .port ().number (), true );
168+ }
169+
170+ private void processPortRemoval (DeviceEvent event ) {
171+ if (!isRelevantHelper (event )) {
172+ return ;
173+ }
174+
175+ setFlatJumpRulesForPatchPort (event .subject ().id (),
176+ event .port ().number (), false );
177+ }
178+
179+ private void setFlatJumpRulesForPatchPort (DeviceId deviceId ,
180+ PortNumber portNumber ,
181+ boolean install ) {
182+ setFlatJumpRuleForPatchPort (deviceId , portNumber ,
183+ Ethernet .TYPE_IPV4 , install );
184+ setFlatJumpRuleForPatchPort (deviceId , portNumber ,
185+ Ethernet .TYPE_ARP , install );
186+ }
187+
188+ private void setFlatJumpRuleForPatchPort (DeviceId deviceId ,
189+ PortNumber portNumber ,
190+ short ethType , boolean install ) {
191+ TrafficSelector .Builder selector = DefaultTrafficSelector .builder ();
192+ selector .matchInPort (portNumber )
193+ .matchEthType (ethType );
194+
195+ TrafficTreatment .Builder treatment = DefaultTrafficTreatment .builder ();
196+ treatment .transition (STAT_FLAT_OUTBOUND_TABLE );
197+
198+ osFlowRuleService .setRule (
199+ appId ,
200+ deviceId ,
201+ selector .build (),
202+ treatment .build (),
203+ PRIORITY_FLAT_JUMP_UPSTREAM_RULE ,
204+ DHCP_TABLE ,
205+ install );
206+ }
207+ }
208+ }
0 commit comments