From 319252db74d057654287ea03dd39ecab26002d4e Mon Sep 17 00:00:00 2001 From: Matt Peters Date: Thu, 30 May 2019 14:45:26 -0400 Subject: [PATCH] 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 --- cgcs-patch/cgcs-patch/cgcs_patch/base.py | 48 +++++++++++-------- cgcs-patch/cgcs-patch/cgcs_patch/config.py | 1 - cgcs-patch/cgcs-patch/cgcs_patch/constants.py | 2 + .../cgcs-patch/cgcs_patch/patch_agent.py | 13 ++++- .../cgcs-patch/cgcs_patch/patch_controller.py | 32 ++++++++++--- 5 files changed, 65 insertions(+), 31 deletions(-) diff --git a/cgcs-patch/cgcs-patch/cgcs_patch/base.py b/cgcs-patch/cgcs-patch/cgcs_patch/base.py index 6f2fbb7d..105d3e99 100644 --- a/cgcs-patch/cgcs-patch/cgcs_patch/base.py +++ b/cgcs-patch/cgcs-patch/cgcs_patch/base.py @@ -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) diff --git a/cgcs-patch/cgcs-patch/cgcs_patch/config.py b/cgcs-patch/cgcs-patch/cgcs_patch/config.py index 3e2e183b..c3f96f96 100644 --- a/cgcs-patch/cgcs-patch/cgcs_patch/config.py +++ b/cgcs-patch/cgcs-patch/cgcs_patch/config.py @@ -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 diff --git a/cgcs-patch/cgcs-patch/cgcs_patch/constants.py b/cgcs-patch/cgcs-patch/cgcs_patch/constants.py index 3a986a0c..bad7ae41 100644 --- a/cgcs-patch/cgcs-patch/cgcs_patch/constants.py +++ b/cgcs-patch/cgcs-patch/cgcs_patch/constants.py @@ -43,3 +43,5 @@ CLI_OPT_RECURSIVE = '--recursive' CLI_OPT_RELEASE = '--release' ENABLE_DEV_CERTIFICATE_PATCH_IDENTIFIER = 'ENABLE_DEV_CERTIFICATE' + +LOOPBACK_INTERFACE_NAME = "lo" diff --git a/cgcs-patch/cgcs-patch/cgcs_patch/patch_agent.py b/cgcs-patch/cgcs-patch/cgcs_patch/patch_agent.py index c38e7217..86276fb8 100644 --- a/cgcs-patch/cgcs-patch/cgcs_patch/patch_agent.py +++ b/cgcs-patch/cgcs-patch/cgcs_patch/patch_agent.py @@ -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() diff --git a/cgcs-patch/cgcs-patch/cgcs_patch/patch_controller.py b/cgcs-patch/cgcs-patch/cgcs_patch/patch_controller.py index ab3346d3..5ea7686b 100644 --- a/cgcs-patch/cgcs-patch/cgcs_patch/patch_controller.py +++ b/cgcs-patch/cgcs-patch/cgcs_patch/patch_controller.py @@ -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()