diff --git a/neutron/agent/rpc.py b/neutron/agent/rpc.py index 16822033154..6360d38ed5b 100644 --- a/neutron/agent/rpc.py +++ b/neutron/agent/rpc.py @@ -78,10 +78,14 @@ class PluginReportStateAPI(object): doc/source/contributor/internals/rpc_api.rst. """ def __init__(self, topic): - target = oslo_messaging.Target(topic=topic, version='1.0', + target = oslo_messaging.Target(topic=topic, version='1.2', namespace=n_const.RPC_NAMESPACE_STATE) self.client = n_rpc.get_client(target) + def has_alive_neutron_server(self, context, **kwargs): + cctxt = self.client.prepare() + return cctxt.call(context, 'has_alive_neutron_server', **kwargs) + def report_state(self, context, agent_state, use_call=False): cctxt = self.client.prepare( timeout=lib_rpc.TRANSPORT.conf.rpc_response_timeout) diff --git a/neutron/db/agents_db.py b/neutron/db/agents_db.py index 4f555bff90d..358156fd1d8 100644 --- a/neutron/db/agents_db.py +++ b/neutron/db/agents_db.py @@ -461,9 +461,10 @@ class AgentExtRpcCallback(object): API version history: 1.0 - Initial version. 1.1 - report_state now returns agent state. + 1.2 - add method has_alive_neutron_server. """ - target = oslo_messaging.Target(version='1.1', + target = oslo_messaging.Target(version='1.2', namespace=n_const.RPC_NAMESPACE_STATE) START_TIME = timeutils.utcnow() @@ -477,6 +478,9 @@ class AgentExtRpcCallback(object): # Initialize RPC api directed to other neutron-servers self.server_versions_rpc = resources_rpc.ResourcesPushToServersRpcApi() + def has_alive_neutron_server(self, context, **kwargs): + return True + @db_api.retry_if_session_inactive() def report_state(self, context, **kwargs): """Report state from agent to server. diff --git a/neutron/plugins/ml2/drivers/openvswitch/agent/ovs_neutron_agent.py b/neutron/plugins/ml2/drivers/openvswitch/agent/ovs_neutron_agent.py index a9bd3035541..05e409ab576 100644 --- a/neutron/plugins/ml2/drivers/openvswitch/agent/ovs_neutron_agent.py +++ b/neutron/plugins/ml2/drivers/openvswitch/agent/ovs_neutron_agent.py @@ -399,6 +399,18 @@ class OVSNeutronAgent(l2population_rpc.L2populationRpcCallBackTunnelMixin, # RPC network init self.context = context.get_admin_context_without_session() + # Made a simple RPC call to Neutron Server. + while True: + try: + self.state_rpc.has_alive_neutron_server(self.context) + except oslo_messaging.MessagingTimeout as e: + LOG.warning('l2-agent cannot contact neutron server. ' + 'Check connectivity to neutron server. ' + 'Retrying... ' + 'Detailed message: %(msg)s.', {'msg': e}) + continue + break + # Define the listening consumers for the agent consumers = [[constants.TUNNEL, topics.UPDATE], [constants.TUNNEL, topics.DELETE], @@ -1221,6 +1233,17 @@ class OVSNeutronAgent(l2population_rpc.L2populationRpcCallBackTunnelMixin, self.int_ofports[physical_network] = int_ofport self.phys_ofports[physical_network] = phys_ofport + # These two drop flows are the root cause for the bug #1803919. + # And now we add a rpc check during agent start procedure. If + # ovs agent can not reach any neutron server, or all neutron + # servers are down, these flows will not be installed anymore. + # Bug #1803919 was fixed in that way. + # And as a reminder, we can not do much work on this. Because + # the bridge mappings can be varied. Provider (external) network + # can be implicitly set on any physical bridge due to the basic + # NORMAL flow. Different vlan range networks can also have many + # bridge map settings, these tenant network traffic can also be + # blocked by the following drop flows. # block all untranslated traffic between bridges self.int_br.drop_port(in_port=int_ofport) br.drop_port(in_port=phys_ofport) diff --git a/neutron/tests/unit/plugins/ml2/drivers/openvswitch/agent/test_ovs_neutron_agent.py b/neutron/tests/unit/plugins/ml2/drivers/openvswitch/agent/test_ovs_neutron_agent.py index 1411fc33363..d7f12ad3d43 100644 --- a/neutron/tests/unit/plugins/ml2/drivers/openvswitch/agent/test_ovs_neutron_agent.py +++ b/neutron/tests/unit/plugins/ml2/drivers/openvswitch/agent/test_ovs_neutron_agent.py @@ -143,7 +143,9 @@ class TestOvsNeutronAgent(object): new=MockFixedIntervalLoopingCall),\ mock.patch( 'neutron.agent.common.ovs_lib.OVSBridge.' 'get_vif_ports', - return_value=[]): + return_value=[]),\ + mock.patch('neutron.agent.rpc.PluginReportStateAPI.' + 'has_alive_neutron_server'): ext_manager = mock.Mock() agent = self.mod_agent.OVSNeutronAgent(self._bridge_classes(), ext_manager, cfg.CONF) @@ -200,7 +202,9 @@ class TestOvsNeutronAgent(object): return_value=[]), \ mock.patch('neutron.agent.common.ovs_lib.BaseOVS.config', new_callable=mock.PropertyMock, - return_value={'datapath_types': ['netdev']}): + return_value={'datapath_types': ['netdev']}),\ + mock.patch('neutron.agent.rpc.PluginReportStateAPI.' + 'has_alive_neutron_server'): # validate setting non default datapath expected = constants.OVS_DATAPATH_NETDEV cfg.CONF.set_override('datapath_type', @@ -245,7 +249,9 @@ class TestOvsNeutronAgent(object): new=MockFixedIntervalLoopingCall), \ mock.patch( 'neutron.agent.common.ovs_lib.OVSBridge.' 'get_vif_ports', - return_value=[]): + return_value=[]),\ + mock.patch('neutron.agent.rpc.PluginReportStateAPI.' + 'has_alive_neutron_server'): # validate setting non default agent_type expected = 'alt agent type' cfg.CONF.set_override('agent_type', @@ -2440,7 +2446,9 @@ class AncillaryBridgesTest(object): return_value=[]),\ mock.patch( 'neutron.agent.common.ovs_lib.OVSBridge.' 'get_vif_ports', - return_value=[]): + return_value=[]),\ + mock.patch('neutron.agent.rpc.PluginReportStateAPI.' + 'has_alive_neutron_server'): ext_manager = mock.Mock() self.agent = self.mod_agent.OVSNeutronAgent(self._bridge_classes(), ext_manager, cfg.CONF) @@ -2478,7 +2486,9 @@ class AncillaryBridgesTest(object): side_effect=ancillary), \ mock.patch('neutron.agent.common.ovs_lib.OVSBridge.' 'get_vif_port_set', - return_value=vif_port_set): + return_value=vif_port_set),\ + mock.patch('neutron.agent.rpc.PluginReportStateAPI.' + 'has_alive_neutron_server'): ext_manager = mock.Mock() self.agent = self.mod_agent.OVSNeutronAgent(self._bridge_classes(), ext_manager, cfg.CONF) @@ -2555,7 +2565,9 @@ class TestOvsDvrNeutronAgent(object): return_value=[]),\ mock.patch( 'neutron.agent.common.ovs_lib.OVSBridge.' 'get_vif_ports', - return_value=[]): + return_value=[]),\ + mock.patch('neutron.agent.rpc.PluginReportStateAPI.' + 'has_alive_neutron_server'): ext_manager = mock.Mock() self.agent = self.mod_agent.OVSNeutronAgent(self._bridge_classes(), ext_manager, cfg.CONF) diff --git a/neutron/tests/unit/plugins/ml2/drivers/openvswitch/agent/test_ovs_tunnel.py b/neutron/tests/unit/plugins/ml2/drivers/openvswitch/agent/test_ovs_tunnel.py index d0cf4b408ea..1832186f3d4 100644 --- a/neutron/tests/unit/plugins/ml2/drivers/openvswitch/agent/test_ovs_tunnel.py +++ b/neutron/tests/unit/plugins/ml2/drivers/openvswitch/agent/test_ovs_tunnel.py @@ -129,6 +129,9 @@ class TunnelTest(object): 'int-%s' % self.MAP_TUN_BRIDGE: self.MAP_TUN_INT_OFPORT } + mock.patch('neutron.agent.rpc.PluginReportStateAPI.' + 'has_alive_neutron_server').start() + def lookup_br(br_name, *args, **kwargs): return self.ovs_bridges[br_name]