"Fossies" - the Fresh Open Source Software Archive 
Member "neutron-14.0.3/neutron/plugins/ml2/drivers/openvswitch/agent/openflow/native/br_int.py" (22 Oct 2019, 14504 Bytes) of package /linux/misc/openstack/neutron-14.0.3.tar.gz:
As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) Python source code syntax highlighting (style:
standard) with prefixed line numbers.
Alternatively you can here
view or
download the uninterpreted source code file.
For more information about "br_int.py" see the
Fossies "Dox" file reference documentation and the latest
Fossies "Diffs" side-by-side code changes report:
14.0.2_vs_14.0.3.
1 # Copyright (C) 2014,2015 VA Linux Systems Japan K.K.
2 # Copyright (C) 2014,2015 YAMAMOTO Takashi <yamamoto at valinux co jp>
3 # All Rights Reserved.
4 #
5 # Licensed under the Apache License, Version 2.0 (the "License"); you may
6 # not use this file except in compliance with the License. You may obtain
7 # a copy of the License at
8 #
9 # http://www.apache.org/licenses/LICENSE-2.0
10 #
11 # Unless required by applicable law or agreed to in writing, software
12 # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
13 # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
14 # License for the specific language governing permissions and limitations
15 # under the License.
16
17 """
18 * references
19 ** OVS agent https://wiki.openstack.org/wiki/Ovs-flow-logic
20 """
21
22 import netaddr
23
24 from neutron_lib import constants as p_const
25 from os_ken.lib.packet import ether_types
26 from os_ken.lib.packet import icmpv6
27 from os_ken.lib.packet import in_proto
28 from oslo_log import log as logging
29
30 from neutron.plugins.ml2.drivers.openvswitch.agent.common import constants
31 from neutron.plugins.ml2.drivers.openvswitch.agent.openflow.native \
32 import ovs_bridge
33
34
35 LOG = logging.getLogger(__name__)
36
37
38 class OVSIntegrationBridge(ovs_bridge.OVSAgentBridge):
39 """openvswitch agent br-int specific logic."""
40
41 of_tables = constants.INT_BR_ALL_TABLES
42
43 def setup_default_table(self):
44 self.setup_canary_table()
45 self.install_goto(dest_table_id=constants.TRANSIENT_TABLE)
46 self.install_normal(table_id=constants.TRANSIENT_TABLE, priority=3)
47 self.install_drop(table_id=constants.ARP_SPOOF_TABLE)
48 self.install_drop(table_id=constants.LOCAL_SWITCHING,
49 priority=constants.OPENFLOW_MAX_PRIORITY,
50 vlan_vid=constants.DEAD_VLAN_TAG)
51
52 def setup_canary_table(self):
53 self.install_drop(constants.CANARY_TABLE)
54
55 def check_canary_table(self):
56 try:
57 flows = self.dump_flows(constants.CANARY_TABLE)
58 except RuntimeError:
59 LOG.exception("Failed to communicate with the switch")
60 return constants.OVS_DEAD
61 return constants.OVS_NORMAL if flows else constants.OVS_RESTARTED
62
63 @staticmethod
64 def _local_vlan_match(_ofp, ofpp, port, vlan_vid):
65 return ofpp.OFPMatch(in_port=port, vlan_vid=vlan_vid)
66
67 def provision_local_vlan(self, port, lvid, segmentation_id):
68 (_dp, ofp, ofpp) = self._get_dp()
69 if segmentation_id is None:
70 vlan_vid = ofp.OFPVID_NONE
71 actions = [ofpp.OFPActionPushVlan()]
72 else:
73 vlan_vid = segmentation_id | ofp.OFPVID_PRESENT
74 actions = []
75 match = self._local_vlan_match(ofp, ofpp, port, vlan_vid)
76 actions += [
77 ofpp.OFPActionSetField(vlan_vid=lvid | ofp.OFPVID_PRESENT),
78 ]
79 instructions = [
80 ofpp.OFPInstructionActions(ofp.OFPIT_APPLY_ACTIONS, actions),
81 ofpp.OFPInstructionGotoTable(table_id=constants.TRANSIENT_TABLE),
82 ]
83 self.install_instructions(
84 instructions=instructions,
85 priority=3,
86 match=match,
87 )
88
89 def reclaim_local_vlan(self, port, segmentation_id):
90 (_dp, ofp, ofpp) = self._get_dp()
91 if segmentation_id is None:
92 vlan_vid = ofp.OFPVID_NONE
93 else:
94 vlan_vid = segmentation_id | ofp.OFPVID_PRESENT
95 match = self._local_vlan_match(ofp, ofpp, port, vlan_vid)
96 self.uninstall_flows(match=match)
97
98 @staticmethod
99 def _arp_dvr_dst_mac_match(ofp, ofpp, vlan, dvr_mac):
100 # If eth_dst is equal to the dvr mac of this host, then
101 # flag it as matched.
102 return ofpp.OFPMatch(vlan_vid=vlan | ofp.OFPVID_PRESENT,
103 eth_dst=dvr_mac)
104
105 @staticmethod
106 def _dvr_dst_mac_table_id(network_type):
107 if network_type == p_const.TYPE_VLAN:
108 return constants.ARP_DVR_MAC_TO_DST_MAC_VLAN
109 else:
110 return constants.ARP_DVR_MAC_TO_DST_MAC
111
112 def install_dvr_dst_mac_for_arp(self, network_type,
113 vlan_tag, gateway_mac, dvr_mac, rtr_port):
114 table_id = self._dvr_dst_mac_table_id(network_type)
115 # Match the destination MAC with the DVR MAC
116 (_dp, ofp, ofpp) = self._get_dp()
117 match = self._arp_dvr_dst_mac_match(ofp, ofpp, vlan_tag, dvr_mac)
118 # Incoming packet will come with destination MAC of DVR host MAC from
119 # the ARP Responder. The Source MAC in this case will have the source
120 # MAC of the port MAC that responded from the ARP responder.
121 # So just remove the DVR host MAC from the 'eth_dst' and replace it
122 # with the gateway-mac. The packet should end up in the right the table
123 # for the packet to reach the router interface.
124 actions = [
125 ofpp.OFPActionSetField(eth_dst=gateway_mac),
126 ofpp.OFPActionPopVlan(),
127 ofpp.OFPActionOutput(rtr_port, 0)
128 ]
129 self.install_apply_actions(table_id=table_id,
130 priority=5,
131 match=match,
132 actions=actions)
133
134 @staticmethod
135 def _dvr_to_src_mac_match(ofp, ofpp, vlan_tag, dst_mac):
136 return ofpp.OFPMatch(vlan_vid=vlan_tag | ofp.OFPVID_PRESENT,
137 eth_dst=dst_mac)
138
139 @staticmethod
140 def _dvr_to_src_mac_table_id(network_type):
141 if network_type == p_const.TYPE_VLAN:
142 return constants.DVR_TO_SRC_MAC_VLAN
143 else:
144 return constants.DVR_TO_SRC_MAC
145
146 def install_dvr_to_src_mac(self, network_type,
147 vlan_tag, gateway_mac, dst_mac, dst_port):
148 table_id = self._dvr_to_src_mac_table_id(network_type)
149 (_dp, ofp, ofpp) = self._get_dp()
150 match = self._dvr_to_src_mac_match(ofp, ofpp,
151 vlan_tag=vlan_tag, dst_mac=dst_mac)
152 actions = [
153 ofpp.OFPActionSetField(eth_src=gateway_mac),
154 ]
155 instructions = [
156 ofpp.OFPInstructionActions(ofp.OFPIT_APPLY_ACTIONS, actions),
157 ofpp.OFPInstructionGotoTable(table_id=constants.TRANSIENT_TABLE),
158 ]
159 self.install_instructions(table_id=table_id,
160 priority=4,
161 match=match,
162 instructions=instructions)
163 actions = [
164 ofpp.OFPActionPopVlan(),
165 ofpp.OFPActionOutput(dst_port, 0),
166 ]
167 self.install_apply_actions(table_id=constants.TRANSIENT_TABLE,
168 priority=4,
169 match=match,
170 actions=actions)
171
172 def delete_dvr_to_src_mac(self, network_type, vlan_tag, dst_mac):
173 table_id = self._dvr_to_src_mac_table_id(network_type)
174 (_dp, ofp, ofpp) = self._get_dp()
175 match = self._dvr_to_src_mac_match(ofp, ofpp,
176 vlan_tag=vlan_tag, dst_mac=dst_mac)
177 for table in (table_id, constants.TRANSIENT_TABLE):
178 self.uninstall_flows(
179 strict=True, priority=4, table_id=table, match=match)
180
181 def add_dvr_mac_vlan(self, mac, port):
182 self.install_goto(table_id=constants.LOCAL_SWITCHING,
183 priority=4,
184 in_port=port,
185 eth_src=mac,
186 dest_table_id=constants.DVR_TO_SRC_MAC_VLAN)
187
188 def remove_dvr_mac_vlan(self, mac):
189 # REVISIT(yamamoto): match in_port as well?
190 self.uninstall_flows(table_id=constants.LOCAL_SWITCHING,
191 eth_src=mac)
192
193 def add_dvr_mac_tun(self, mac, port):
194 self.install_goto(table_id=constants.LOCAL_SWITCHING,
195 priority=2,
196 in_port=port,
197 eth_src=mac,
198 dest_table_id=constants.DVR_TO_SRC_MAC)
199
200 def remove_dvr_mac_tun(self, mac, port):
201 self.uninstall_flows(table_id=constants.LOCAL_SWITCHING,
202 in_port=port, eth_src=mac)
203
204 def delete_dvr_dst_mac_for_arp(self, network_type,
205 vlan_tag, gateway_mac, dvr_mac, rtr_port):
206 table_id = self._dvr_to_src_mac_table_id(network_type)
207 (_dp, ofp, ofpp) = self._get_dp()
208 match = self._arp_dvr_dst_mac_match(ofp, ofpp, vlan_tag, dvr_mac)
209 for table in table_id:
210 self.uninstall_flows(
211 strict=True, priority=5, table_id=table, match=match)
212
213 def add_dvr_gateway_mac_arp_vlan(self, mac, port):
214 self.install_goto(table_id=constants.LOCAL_SWITCHING,
215 priority=5,
216 in_port=port,
217 eth_dst=mac,
218 dest_table_id=constants.ARP_DVR_MAC_TO_DST_MAC_VLAN)
219
220 def remove_dvr_gateway_mac_arp_vlan(self, mac, port):
221 self.uninstall_flows(table_id=constants.LOCAL_SWITCHING,
222 eth_dst=mac)
223
224 def add_dvr_gateway_mac_arp_tun(self, mac, port):
225 self.install_goto(table_id=constants.LOCAL_SWITCHING,
226 priority=5,
227 in_port=port,
228 eth_dst=mac,
229 dest_table_id=constants.ARP_DVR_MAC_TO_DST_MAC)
230
231 def remove_dvr_gateway_mac_arp_tun(self, mac, port):
232 self.uninstall_flows(table_id=constants.LOCAL_SWITCHING,
233 eth_dst=mac)
234
235 @staticmethod
236 def _arp_reply_match(ofp, ofpp, port):
237 return ofpp.OFPMatch(in_port=port,
238 eth_type=ether_types.ETH_TYPE_ARP)
239
240 @staticmethod
241 def _icmpv6_reply_match(ofp, ofpp, port):
242 return ofpp.OFPMatch(in_port=port,
243 eth_type=ether_types.ETH_TYPE_IPV6,
244 ip_proto=in_proto.IPPROTO_ICMPV6,
245 icmpv6_type=icmpv6.ND_NEIGHBOR_ADVERT)
246
247 def install_icmpv6_na_spoofing_protection(self, port, ip_addresses):
248 # Allow neighbor advertisements as long as they match addresses
249 # that actually belong to the port.
250 for ip in ip_addresses:
251 masked_ip = self._cidr_to_os_ken(ip)
252 self.install_goto(
253 table_id=constants.ARP_SPOOF_TABLE, priority=2,
254 eth_type=ether_types.ETH_TYPE_IPV6,
255 ip_proto=in_proto.IPPROTO_ICMPV6,
256 icmpv6_type=icmpv6.ND_NEIGHBOR_ADVERT,
257 ipv6_nd_target=masked_ip, in_port=port,
258 dest_table_id=constants.TRANSIENT_TABLE)
259
260 # Now that the rules are ready, direct icmpv6 neighbor advertisement
261 # traffic from the port into the anti-spoof table.
262 (_dp, ofp, ofpp) = self._get_dp()
263 match = self._icmpv6_reply_match(ofp, ofpp, port=port)
264 self.install_goto(table_id=constants.LOCAL_SWITCHING,
265 priority=10,
266 match=match,
267 dest_table_id=constants.ARP_SPOOF_TABLE)
268
269 def set_allowed_macs_for_port(self, port, mac_addresses=None,
270 allow_all=False):
271 if allow_all:
272 self.uninstall_flows(table_id=constants.LOCAL_SWITCHING,
273 in_port=port)
274 self.uninstall_flows(table_id=constants.MAC_SPOOF_TABLE,
275 in_port=port)
276 return
277 mac_addresses = mac_addresses or []
278 for address in mac_addresses:
279 self.install_goto(
280 table_id=constants.MAC_SPOOF_TABLE, priority=2,
281 eth_src=address, in_port=port,
282 dest_table_id=constants.TRANSIENT_TABLE)
283 # normalize so we can see if macs are the same
284 mac_addresses = {netaddr.EUI(mac) for mac in mac_addresses}
285 flows = self.dump_flows(constants.MAC_SPOOF_TABLE)
286 for flow in flows:
287 matches = dict(flow.match.items())
288 if matches.get('in_port') != port:
289 continue
290 if not matches.get('eth_src'):
291 continue
292 flow_mac = matches['eth_src']
293 if netaddr.EUI(flow_mac) not in mac_addresses:
294 self.uninstall_flows(table_id=constants.MAC_SPOOF_TABLE,
295 in_port=port, eth_src=flow_mac)
296 self.install_goto(table_id=constants.LOCAL_SWITCHING,
297 priority=9, in_port=port,
298 dest_table_id=constants.MAC_SPOOF_TABLE)
299
300 def install_arp_spoofing_protection(self, port, ip_addresses):
301 # allow ARP replies as long as they match addresses that actually
302 # belong to the port.
303 for ip in ip_addresses:
304 masked_ip = self._cidr_to_os_ken(ip)
305 self.install_goto(table_id=constants.ARP_SPOOF_TABLE,
306 priority=2,
307 eth_type=ether_types.ETH_TYPE_ARP,
308 arp_spa=masked_ip,
309 in_port=port,
310 dest_table_id=constants.MAC_SPOOF_TABLE)
311
312 # Now that the rules are ready, direct ARP traffic from the port into
313 # the anti-spoof table.
314 # This strategy fails gracefully because OVS versions that can't match
315 # on ARP headers will just process traffic normally.
316 (_dp, ofp, ofpp) = self._get_dp()
317 match = self._arp_reply_match(ofp, ofpp, port=port)
318 self.install_goto(table_id=constants.LOCAL_SWITCHING,
319 priority=10,
320 match=match,
321 dest_table_id=constants.ARP_SPOOF_TABLE)
322
323 def delete_arp_spoofing_protection(self, port):
324 (_dp, ofp, ofpp) = self._get_dp()
325 match = self._arp_reply_match(ofp, ofpp, port=port)
326 self.uninstall_flows(table_id=constants.LOCAL_SWITCHING,
327 match=match)
328 match = self._icmpv6_reply_match(ofp, ofpp, port=port)
329 self.uninstall_flows(table_id=constants.LOCAL_SWITCHING,
330 match=match)
331 self.delete_arp_spoofing_allow_rules(port)
332
333 def delete_arp_spoofing_allow_rules(self, port):
334 self.uninstall_flows(table_id=constants.ARP_SPOOF_TABLE,
335 in_port=port)