patching service unicast messaging for loopback interface

IPv6 does not support multicast messaging on the loopback interface.
Therefore to support patch agent to controller messaging when the
management network is associated with the loopback interface it
must operate using unicast messaging.  This is sufficient since it
does not need to communicate with multiple process instances when
operating in this local mode.

Change-Id: I95efd06be9717a76ccbd543c1fd16408fd89dbeb
Closes-Bug: #1830779
Signed-off-by: Matt Peters <matt.peters@windriver.com>
This commit is contained in:
Matt Peters 2019-05-30 14:45:26 -04:00
parent 4b1e9e453f
commit 319252db74
5 changed files with 65 additions and 31 deletions

View File

@ -64,18 +64,19 @@ class PatchService:
self.sock_out.bind((mgmt_ip, 0))
self.sock_in.bind(('', self.port))
# These options are for outgoing multicast messages
self.sock_out.setsockopt(socket.IPPROTO_IP, socket.IP_MULTICAST_IF, interface_addr)
self.sock_out.setsockopt(socket.IPPROTO_IP, socket.IP_MULTICAST_TTL, 1)
# Since only the controllers are sending to this address,
# we want the loopback so the local agent can receive it
self.sock_out.setsockopt(socket.IPPROTO_IP, socket.IP_MULTICAST_LOOP, 1)
if self.mcast_addr:
# These options are for outgoing multicast messages
self.sock_out.setsockopt(socket.IPPROTO_IP, socket.IP_MULTICAST_IF, interface_addr)
self.sock_out.setsockopt(socket.IPPROTO_IP, socket.IP_MULTICAST_TTL, 1)
# Since only the controllers are sending to this address,
# we want the loopback so the local agent can receive it
self.sock_out.setsockopt(socket.IPPROTO_IP, socket.IP_MULTICAST_LOOP, 1)
# Register the multicast group
group = socket.inet_pton(socket.AF_INET, self.mcast_addr)
mreq = struct.pack('=4s4s', group, interface_addr)
# Register the multicast group
group = socket.inet_pton(socket.AF_INET, self.mcast_addr)
mreq = struct.pack('=4s4s', group, interface_addr)
self.sock_in.setsockopt(socket.IPPROTO_IP, socket.IP_ADD_MEMBERSHIP, mreq)
self.sock_in.setsockopt(socket.IPPROTO_IP, socket.IP_ADD_MEMBERSHIP, mreq)
return self.sock_in
@ -106,18 +107,19 @@ class PatchService:
self.sock_out.bind((mgmt_ip, 0))
self.sock_in.bind(('', self.port))
# These options are for outgoing multicast messages
mgmt_ifindex = utils.if_nametoindex(cfg.get_mgmt_iface())
self.sock_out.setsockopt(socket.IPPROTO_IPV6, socket.IPV6_MULTICAST_IF, mgmt_ifindex)
self.sock_out.setsockopt(socket.IPPROTO_IPV6, socket.IPV6_MULTICAST_HOPS, 1)
# Since only the controllers are sending to this address,
# we want the loopback so the local agent can receive it
self.sock_out.setsockopt(socket.IPPROTO_IPV6, socket.IPV6_MULTICAST_LOOP, 1)
if self.mcast_addr:
# These options are for outgoing multicast messages
mgmt_ifindex = utils.if_nametoindex(cfg.get_mgmt_iface())
self.sock_out.setsockopt(socket.IPPROTO_IPV6, socket.IPV6_MULTICAST_IF, mgmt_ifindex)
self.sock_out.setsockopt(socket.IPPROTO_IPV6, socket.IPV6_MULTICAST_HOPS, 1)
# Since only the controllers are sending to this address,
# we want the loopback so the local agent can receive it
self.sock_out.setsockopt(socket.IPPROTO_IPV6, socket.IPV6_MULTICAST_LOOP, 1)
# Register the multicast group
if_index_packed = struct.pack('I', mgmt_ifindex)
group = socket.inet_pton(socket.AF_INET6, self.mcast_addr) + if_index_packed
self.sock_in.setsockopt(socket.IPPROTO_IPV6, socket.IPV6_JOIN_GROUP, group)
# Register the multicast group
if_index_packed = struct.pack('I', mgmt_ifindex)
group = socket.inet_pton(socket.AF_INET6, self.mcast_addr) + if_index_packed
self.sock_in.setsockopt(socket.IPPROTO_IPV6, socket.IPV6_JOIN_GROUP, group)
return self.sock_in
@ -145,6 +147,10 @@ class PatchService:
return None
def audit_socket(self):
if not self.mcast_addr:
# Multicast address not configured, therefore nothing to do
return
# Ensure multicast address is still allocated
cmd = "ip maddr show %s | awk 'BEGIN {ORS=\"\"}; {if ($2 == \"%s\") print $2}'" % \
(cfg.get_mgmt_iface(), self.mcast_addr)

View File

@ -114,7 +114,6 @@ def get_mgmt_iface():
try:
value = str(config.get('platform_conf', 'management_interface'))
global nodetype
mgmt_if = value
platform_conf_mtime = os.stat(tsc.PLATFORM_CONF_FILE).st_mtime

View File

@ -43,3 +43,5 @@ CLI_OPT_RECURSIVE = '--recursive'
CLI_OPT_RELEASE = '--release'
ENABLE_DEV_CERTIFICATE_PATCH_IDENTIFIER = 'ENABLE_DEV_CERTIFICATE'
LOOPBACK_INTERFACE_NAME = "lo"

View File

@ -172,9 +172,10 @@ class PatchMessageHelloAgentAck(messages.PatchMessage):
LOG.error("Should not get here")
def send(self, sock):
global pa
self.encode()
message = json.dumps(self.message)
sock.sendto(message, (cfg.controller_mcast_group, cfg.controller_port))
sock.sendto(message, (pa.controller_address, cfg.controller_port))
class PatchMessageQueryDetailed(messages.PatchMessage):
@ -292,6 +293,7 @@ class PatchAgent(PatchService):
PatchService.__init__(self)
self.sock_out = None
self.sock_in = None
self.controller_address = None
self.listener = None
self.changes = False
self.installed = {}
@ -323,8 +325,15 @@ class PatchAgent(PatchService):
if self.port != cfg.agent_port:
self.port = cfg.agent_port
if self.mcast_addr != cfg.agent_mcast_group:
# Loopback interface does not support multicast messaging, therefore
# revert to using unicast messaging when configured against the
# loopback device
if cfg.get_mgmt_iface() == constants.LOOPBACK_INTERFACE_NAME:
self.mcast_addr = None
self.controller_address = cfg.get_mgmt_ip()
else:
self.mcast_addr = cfg.agent_mcast_group
self.controller_address = cfg.controller_mcast_group
def setup_tcp_socket(self):
address_family = utils.get_management_family()

View File

@ -230,9 +230,10 @@ class PatchMessageHello(messages.PatchMessage):
resp.send(sock)
def send(self, sock):
global pc
self.encode()
message = json.dumps(self.message)
sock.sendto(message, (cfg.controller_mcast_group, cfg.controller_port))
sock.sendto(message, (pc.controller_address, cfg.controller_port))
class PatchMessageHelloAck(messages.PatchMessage):
@ -254,9 +255,10 @@ class PatchMessageHelloAck(messages.PatchMessage):
pc.controller_neighbours_lock.release()
def send(self, sock):
global pc
self.encode()
message = json.dumps(self.message)
sock.sendto(message, (cfg.controller_mcast_group, cfg.controller_port))
sock.sendto(message, (pc.controller_address, cfg.controller_port))
class PatchMessageSyncReq(messages.PatchMessage):
@ -283,10 +285,11 @@ class PatchMessageSyncReq(messages.PatchMessage):
resp.send(sock)
def send(self, sock):
global pc
LOG.info("sending sync req")
self.encode()
message = json.dumps(self.message)
sock.sendto(message, (cfg.controller_mcast_group, cfg.controller_port))
sock.sendto(message, (pc.controller_address, cfg.controller_port))
class PatchMessageSyncComplete(messages.PatchMessage):
@ -309,10 +312,11 @@ class PatchMessageSyncComplete(messages.PatchMessage):
pc.controller_neighbours_lock.release()
def send(self, sock):
global pc
LOG.info("sending sync complete")
self.encode()
message = json.dumps(self.message)
sock.sendto(message, (cfg.controller_mcast_group, cfg.controller_port))
sock.sendto(message, (pc.controller_address, cfg.controller_port))
class PatchMessageHelloAgent(messages.PatchMessage):
@ -328,10 +332,11 @@ class PatchMessageHelloAgent(messages.PatchMessage):
LOG.error("Should not get here")
def send(self, sock):
global pc
self.encode()
message = json.dumps(self.message)
local_hostname = utils.ip_to_versioned_localhost(cfg.agent_mcast_group)
sock.sendto(message, (cfg.agent_mcast_group, cfg.agent_port))
sock.sendto(message, (pc.agent_address, cfg.agent_port))
sock.sendto(message, (local_hostname, cfg.agent_port))
@ -549,9 +554,10 @@ class PatchMessageDropHostReq(messages.PatchMessage):
return
def send(self, sock):
global pc
self.encode()
message = json.dumps(self.message)
sock.sendto(message, (cfg.controller_mcast_group, cfg.controller_port))
sock.sendto(message, (pc.controller_address, cfg.controller_port))
class PatchController(PatchService):
@ -577,6 +583,8 @@ class PatchController(PatchService):
self.sock_out = None
self.sock_in = None
self.controller_address = None
self.agent_address = None
self.patch_op_counter = 1
self.patch_data = PatchData()
self.patch_data.load_all()
@ -605,8 +613,18 @@ class PatchController(PatchService):
if self.port != cfg.controller_port:
self.port = cfg.controller_port
if self.mcast_addr != cfg.controller_mcast_group:
# Loopback interface does not support multicast messaging, therefore
# revert to using unicast messaging when configured against the
# loopback device
if cfg.get_mgmt_iface() == constants.LOOPBACK_INTERFACE_NAME:
mgmt_ip = cfg.get_mgmt_ip()
self.mcast_addr = None
self.controller_address = mgmt_ip
self.agent_address = mgmt_ip
else:
self.mcast_addr = cfg.controller_mcast_group
self.controller_address = cfg.controller_mcast_group
self.agent_address = cfg.agent_mcast_group
def socket_lock_acquire(self):
self.socket_lock.acquire()