1 # Copyright (c) 2013 OpenStack Foundation.
4 # Licensed under the Apache License, Version 2.0 (the "License"); you may
5 # not use this file except in compliance with the License. You may obtain
6 # a copy of the License at
8 # http://www.apache.org/licenses/LICENSE-2.0
10 # Unless required by applicable law or agreed to in writing, software
11 # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12 # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13 # License for the specific language governing permissions and limitations
18 from oslo_config import cfg
19 from oslo_log import helpers as log_helpers
22 from neutron.common import constants as n_const
23 from neutron.plugins.ml2.drivers.l2pop import rpc as l2pop_rpc
26 @six.add_metaclass(abc.ABCMeta)
27 class L2populationRpcCallBackMixin(object):
28 '''General mixin class of L2-population RPC call back.
30 The following methods are called through RPC.
31 add_fdb_entries(), remove_fdb_entries(), update_fdb_entries()
32 The following methods are used in an agent as internal methods.
33 fdb_add(), fdb_remove(), fdb_update()
36 @log_helpers.log_method_call
37 def add_fdb_entries(self, context, fdb_entries, host=None):
38 if not host or host == cfg.CONF.host:
39 self.fdb_add(context, self._unmarshall_fdb_entries(fdb_entries))
41 @log_helpers.log_method_call
42 def remove_fdb_entries(self, context, fdb_entries, host=None):
43 if not host or host == cfg.CONF.host:
44 self.fdb_remove(context, self._unmarshall_fdb_entries(fdb_entries))
46 @log_helpers.log_method_call
47 def update_fdb_entries(self, context, fdb_entries, host=None):
48 if not host or host == cfg.CONF.host:
49 self.fdb_update(context, self._unmarshall_fdb_entries(fdb_entries))
52 def _unmarshall_fdb_entries(fdb_entries):
53 """Prepares fdb_entries from JSON.
55 All methods in this class that receive messages should call this to
56 unmarshall fdb_entries from the wire.
58 :param fdb_entries: Original fdb_entries data-structure. Looks like:
63 <ip address>: [ [<mac>, <ip>], ... ],
66 :returns: Deep copy with [<mac>, <ip>] converted to PortInfo
68 unmarshalled = dict(fdb_entries)
69 for value in unmarshalled.values():
71 value['ports'] = dict(
72 (address, [l2pop_rpc.PortInfo(*pi) for pi in port_infos])
73 for address, port_infos in value['ports'].items()
78 def fdb_add(self, context, fdb_entries):
82 def fdb_remove(self, context, fdb_entries):
86 def fdb_update(self, context, fdb_entries):
90 class L2populationRpcCallBackTunnelMixin(L2populationRpcCallBackMixin):
91 '''Mixin class of L2-population call back for Tunnel.
93 The following methods are all used in agents as internal methods.
95 Some of the methods in this class use Local VLAN Mapping, aka lvm.
96 It's a python object with at least the following attributes:
98 ============ =========================================================
100 ============ =========================================================
101 vlan An identifier used by the agent to identify a neutron
103 network_type A network type found in neutron.plugins.common.constants.
104 ============ =========================================================
106 NOTE(yamamoto): "Local VLAN" is an OVS-agent term. OVS-agent internally
107 uses 802.1q VLAN tagging to isolate networks. While this class inherited
108 the terms from OVS-agent, it does not assume the specific underlying
109 technologies. E.g. this class is also used by ofagent, where a different
114 def add_fdb_flow(self, br, port_info, remote_ip, lvm, ofport):
117 This method is assumed to be used by method fdb_add_tun.
118 We expect to add a flow entry to send a packet to specified port
120 And you may edit some information for local arp response.
122 :param br: represent the bridge on which add_fdb_flow should be
124 :param port_info: PortInfo instance to include mac and ip.
128 :remote_ip: remote ip address.
129 :param lvm: a local VLAN map of network.
130 :param ofport: a port to add.
135 def del_fdb_flow(self, br, port_info, remote_ip, lvm, ofport):
136 '''Delete flow for fdb
138 This method is assumed to be used by method fdb_remove_tun.
139 We expect to delete a flow entry to send a packet to specified port
141 And you may delete some information for local arp response.
143 :param br: represent the bridge on which del_fdb_flow should be
145 :param port_info: PortInfo instance to include mac and ip.
149 :remote_ip: remote ip address.
150 :param lvm: local VLAN map of a network. See add_fdb_flow for
152 :param ofport: a port to delete.
157 def setup_tunnel_port(self, br, remote_ip, network_type):
158 '''Setup an added tunnel port.
160 This method is assumed to be used by method fdb_add_tun.
161 We expect to prepare to call add_fdb_flow. It will be mainly adding
163 If you need, you may do some preparations for a bridge.
165 :param br: represent the bridge on which setup_tunnel_port should be
167 :param remote_ip: an ip for a port to setup.
168 :param network_type: a type of a network.
169 :returns: an ofport value. value 0 means the port is unavailable.
174 def cleanup_tunnel_port(self, br, tun_ofport, tunnel_type):
175 '''Clean up a deleted tunnel port.
177 This method is assumed to be used by method fdb_remove_tun.
178 We expect to clean up after calling del_fdb_flow. It will be mainly
179 deleting a port from a bridge.
180 If you need, you may do some cleanup for a bridge.
182 :param br: represent the bridge on which cleanup_tunnel_port should be
184 :param tun_ofport: a port value to cleanup.
185 :param tunnel_type: a type of a tunnel.
190 def setup_entry_for_arp_reply(self, br, action, local_vid, mac_address,
192 '''Operate the ARP respond information.
194 Update MAC/IPv4 associations, which is typically used by
195 the local ARP responder. For example, OVS-agent sets up
196 flow entries to perform ARP responses.
198 :param br: represent the bridge on which setup_entry_for_arp_reply
200 :param action: add/remove flow for arp response information.
201 :param local_vid: id in local VLAN map of network's ARP entry.
202 :param mac_address: MAC string value.
203 :param ip_address: IP string value.
207 def get_agent_ports(self, fdb_entries, local_vlan_map):
208 """Generator to yield port info.
210 For each known (i.e found in local_vlan_map) network in
211 fdb_entries, yield (lvm, fdb_entries[network_id]['ports']) pair.
213 :param fdb_entries: l2pop fdb entries
214 :param local_vlan_map: A dict to map network_id to
215 the corresponding lvm entry.
217 for network_id, values in fdb_entries.items():
218 lvm = local_vlan_map.get(network_id)
221 agent_ports = values.get('ports')
222 yield (lvm, agent_ports)
224 @log_helpers.log_method_call
225 def fdb_add_tun(self, context, br, lvm, agent_ports, lookup_port):
226 for remote_ip, ports in agent_ports.items():
227 # Ensure we have a tunnel port with this remote agent
228 ofport = lookup_port(lvm.network_type, remote_ip)
230 ofport = self.setup_tunnel_port(br, remote_ip,
235 self.add_fdb_flow(br, port, remote_ip, lvm, ofport)
237 @log_helpers.log_method_call
238 def fdb_remove_tun(self, context, br, lvm, agent_ports, lookup_port):
239 for remote_ip, ports in agent_ports.items():
240 ofport = lookup_port(lvm.network_type, remote_ip)
244 self.del_fdb_flow(br, port, remote_ip, lvm, ofport)
245 if port == n_const.FLOODING_ENTRY:
246 # Check if this tunnel port is still used
247 self.cleanup_tunnel_port(br, ofport, lvm.network_type)
249 @log_helpers.log_method_call
250 def fdb_update(self, context, fdb_entries):
251 '''Call methods named '_fdb_<action>'.
253 This method assumes that methods '_fdb_<action>' are defined in class.
254 Currently the following actions are available.
257 for action, values in fdb_entries.items():
258 method = '_fdb_' + action
259 if not hasattr(self, method):
260 raise NotImplementedError()
262 getattr(self, method)(context, values)
264 @log_helpers.log_method_call
265 def fdb_chg_ip_tun(self, context, br, fdb_entries, local_ip,
267 '''fdb update when an IP of a port is updated.
269 The ML2 l2-pop mechanism driver sends an fdb update rpc message when an
270 IP of a port is updated.
272 :param context: RPC context.
273 :param br: represent the bridge on which fdb_chg_ip_tun should be
275 :param fdb_entries: fdb dicts that contain all mac/IP information per
287 PortInfo has .mac_address and .ip_address attrs.
289 :param local_ip: local IP address of this agent.
290 :param local_vlan_map: A dict to map network_id to
291 the corresponding lvm entry.
294 for network_id, agent_ports in fdb_entries.items():
295 lvm = local_vlan_map.get(network_id)
299 for agent_ip, state in agent_ports.items():
300 if agent_ip == local_ip:
303 after = state.get('after', [])
305 self.setup_entry_for_arp_reply(br, 'add', lvm.vlan,
309 before = state.get('before', [])
310 for mac_ip in before:
311 self.setup_entry_for_arp_reply(br, 'remove', lvm.vlan,