From e583d34555310bfc4db0a234588ba71af4df853d Mon Sep 17 00:00:00 2001 From: Jarrod Johnson Date: Thu, 4 Mar 2021 10:47:28 -0500 Subject: [PATCH 01/14] Fix nic index map with bonding The assumption that /sys/class/net is interfaces is incorrect, when encountering entries that are not interfaces, do not mess up the call. --- confluent_server/confluent/netutil.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/confluent_server/confluent/netutil.py b/confluent_server/confluent/netutil.py index d5123217..f1808144 100644 --- a/confluent_server/confluent/netutil.py +++ b/confluent_server/confluent/netutil.py @@ -82,8 +82,11 @@ _idxtoifnamemap = {} def _rebuildidxmap(): _idxtoifnamemap.clear() for iname in os.listdir('/sys/class/net'): - ci = int(open('/sys/class/net/{0}/ifindex'.format(iname)).read()) - _idxtoifnamemap[ci] = iname + try: + ci = int(open('/sys/class/net/{0}/ifindex'.format(iname)).read()) + _idxtoifnamemap[ci] = iname + except Exception: # there may be non interface in /sys/class/net + pass def myiptonets(svrip): From 5d0423c38b8fa1cdec33ed3857a5cbbdc79a1ffc Mon Sep 17 00:00:00 2001 From: Jarrod Johnson Date: Fri, 5 Mar 2021 13:08:25 -0500 Subject: [PATCH 02/14] Attempt refresh of neigh table on miss When an address is new it may not be in the last captured neighbor table. Induce refresh before deciding that neighbor is unavailable. --- confluent_server/confluent/discovery/protocols/slp.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/confluent_server/confluent/discovery/protocols/slp.py b/confluent_server/confluent/discovery/protocols/slp.py index 30e9de4f..61573039 100644 --- a/confluent_server/confluent/discovery/protocols/slp.py +++ b/confluent_server/confluent/discovery/protocols/slp.py @@ -107,6 +107,8 @@ def _parse_slp_packet(packet, peer, rsps, xidmap): if '%' in addr: addr = addr[:addr.index('%')] mac = None + if addr not in neighutil.neightable: + neighutil.update_neigh() if addr in neighutil.neightable: identifier = neighutil.neightable[addr] mac = identifier From c9157b90eb3d24398310470c3be3635fb4ea385f Mon Sep 17 00:00:00 2001 From: Jarrod Johnson Date: Fri, 5 Mar 2021 13:14:41 -0500 Subject: [PATCH 03/14] Close other places that may be false negative Have checks for neightable be preceeded by an attempt to refresh, to mitigate false negatives. --- confluent_server/confluent/discovery/protocols/slp.py | 2 ++ confluent_server/confluent/discovery/protocols/ssdp.py | 4 ++++ 2 files changed, 6 insertions(+) diff --git a/confluent_server/confluent/discovery/protocols/slp.py b/confluent_server/confluent/discovery/protocols/slp.py index 61573039..8542465b 100644 --- a/confluent_server/confluent/discovery/protocols/slp.py +++ b/confluent_server/confluent/discovery/protocols/slp.py @@ -535,6 +535,8 @@ def active_scan(handler, protocol=None): for scanned in scan(): for addr in scanned['addresses']: ip = addr[0].partition('%')[0] # discard scope if present + if ip not in neighutil.neightable: + neighutil.update_neigh() if ip not in neighutil.neightable: continue if addr in known_peers: diff --git a/confluent_server/confluent/discovery/protocols/ssdp.py b/confluent_server/confluent/discovery/protocols/ssdp.py index 456fb1c4..c14b9b77 100644 --- a/confluent_server/confluent/discovery/protocols/ssdp.py +++ b/confluent_server/confluent/discovery/protocols/ssdp.py @@ -62,6 +62,8 @@ def active_scan(handler, protocol=None): for scanned in scan(['urn:dmtf-org:service:redfish-rest:1']): for addr in scanned['addresses']: ip = addr[0].partition('%')[0] # discard scope if present + if ip not in neighutil.neightable: + neighutil.update_neigh() if ip not in neighutil.neightable: continue if addr in known_peers: @@ -311,6 +313,8 @@ def _parse_ssdp(peer, rsp, peerdata): ip = peer[0].partition('%')[0] nid = ip mac = None + if ip not in neighutil.neightable: + neighutil.update_neigh() if ip in neighutil.neightable: nid = neighutil.neightable[ip] mac = nid From 94a4a7e20b908883d3d481ffb1a0fd31c496f790 Mon Sep 17 00:00:00 2001 From: Jarrod Johnson Date: Mon, 8 Mar 2021 08:00:47 -0500 Subject: [PATCH 04/14] Fix missing exit code in nomededia nodemedia was not setting return code on exit properly. --- confluent_client/bin/nodemedia | 2 ++ 1 file changed, 2 insertions(+) diff --git a/confluent_client/bin/nodemedia b/confluent_client/bin/nodemedia index bb71a8f4..e7d482af 100644 --- a/confluent_client/bin/nodemedia +++ b/confluent_client/bin/nodemedia @@ -187,5 +187,7 @@ def main(): argparser.print_help() sys.exit(1) handler(noderange, media) + if __name__ == '__main__': main() + sys.exit(exitcode) From 1a7c238b54a6fd939843ce00f4f5ea35917860a0 Mon Sep 17 00:00:00 2001 From: Jarrod Johnson Date: Mon, 8 Mar 2021 02:55:58 -0500 Subject: [PATCH 05/14] Handle malformed json data more gracefully --- confluent_server/confluent/discovery/core.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/confluent_server/confluent/discovery/core.py b/confluent_server/confluent/discovery/core.py index 461ce8bb..5ff5240c 100644 --- a/confluent_server/confluent/discovery/core.py +++ b/confluent_server/confluent/discovery/core.py @@ -811,7 +811,11 @@ def get_smm_neighbor_fingerprints(smmaddr, cv): if ':' in smmaddr: smmaddr = '[{0}]'.format(smmaddr) wc = webclient.SecureHTTPConnection(smmaddr, verifycallback=cv) - neighs = wc.grab_json_response('/scripts/neighdata.json') + try: + neighs = wc.grab_json_response('/scripts/neighdata.json') + except Exception: + log.log({'error': 'Failure getting LLDP information from {}'.format(smmaddr)}) + return if not neighs: return for neigh in neighs: From c53e758170ee4bbddec8246d17644d03b5db3885 Mon Sep 17 00:00:00 2001 From: Jarrod Johnson Date: Wed, 10 Mar 2021 09:51:05 -0500 Subject: [PATCH 06/14] Workaround non-cisco switch crash Querying Cisco MIB on certain firmware levels of non-cisco switches causes a crash. Tolerate and wait a bit to give SNMP a chance to restart. --- confluent_server/confluent/networking/macmap.py | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/confluent_server/confluent/networking/macmap.py b/confluent_server/confluent/networking/macmap.py index 9f84c42a..34d9b4fd 100644 --- a/confluent_server/confluent/networking/macmap.py +++ b/confluent_server/confluent/networking/macmap.py @@ -217,13 +217,18 @@ def _map_switch_backend(args): *([int(x) for x in oid[-6:]]) ) mactobridge[macaddr] = int(bridgeport) - #ciscoiftovlanmap = {} vlanstocheck = set([]) - for vb in conn.walk('.1.3.6.1.4.1.9.9.68.1.2.2.1.2'): - vlanstocheck.add(vb[1]) - #ciscotrunktovlanmap = {} - for vb in conn.walk('.1.3.6.1.4.1.9.9.46.1.6.1.1.5'): - vlanstocheck.add(vb[1]) + try: + #ciscoiftovlanmap = {} + for vb in conn.walk('.1.3.6.1.4.1.9.9.68.1.2.2.1.2'): + vlanstocheck.add(vb[1]) + #ciscotrunktovlanmap = {} + for vb in conn.walk('.1.3.6.1.4.1.9.9.46.1.6.1.1.5'): + vlanstocheck.add(vb[1]) + except Exception: + # We might have crashed snmp on a non-cisco switch + # in such a case, delay 8 seconds to allow recovery to complete + eventlet.sleep(8) if not vlanstocheck: vlanstocheck.add(None) bridgetoifmap = {} From 4f246e6a41008e336350fda00530ca3f322d3917 Mon Sep 17 00:00:00 2001 From: Jarrod Johnson Date: Wed, 10 Mar 2021 13:40:47 -0500 Subject: [PATCH 07/14] Fix compatibility with some switch configurations While some implementations mess up portid and need portdescr instead, others are just the opposite. Tolerate match either by description or name. --- confluent_server/confluent/networking/lldp.py | 17 ++++++++++++----- confluent_server/confluent/networking/macmap.py | 2 ++ 2 files changed, 14 insertions(+), 5 deletions(-) diff --git a/confluent_server/confluent/networking/lldp.py b/confluent_server/confluent/networking/lldp.py index 910bb7de..29b94ede 100644 --- a/confluent_server/confluent/networking/lldp.py +++ b/confluent_server/confluent/networking/lldp.py @@ -139,7 +139,10 @@ def get_fingerprint(switch, port, configmanager, portmatch): continue if info.get('switch', None) != switch: continue - if portmatch(info.get('port'), port): + if portmatch(info.get('portid', None), port): + return ('sha256$' + b64tohex(info['peersha256fingerprint']), + info.get('verified', False)) + elif portmatch(info.get('port', None), port): return ('sha256$' + b64tohex(info['peersha256fingerprint']), info.get('verified', False)) return None, False @@ -235,19 +238,23 @@ def _extract_neighbor_data_b(args): idx = oidindex[0][-1] idxtoifname[idx] = _lldpdesc_to_ifname(sid, idx, str(oidindex[1])) for remotedesc in conn.walk('1.0.8802.1.1.2.1.4.1.1.10'): - iname = idxtoifname[remotedesc[0][-2]] + iname = idxtoifname.get(remotedesc[0][-2], + idxtoportid[remotedesc[0][-2]]) _init_lldp(lldpdata, iname, remotedesc[0][-2], idxtoportid, switch) _extract_extended_desc(lldpdata[iname], remotedesc[1], user) for remotename in conn.walk('1.0.8802.1.1.2.1.4.1.1.9'): - iname = idxtoifname[remotename[0][-2]] + iname = idxtoifname.get(remotename[0][-2], + idxtoportid[remotename[0][-2]]) _init_lldp(lldpdata, iname, remotename[0][-2], idxtoportid, switch) lldpdata[iname]['peername'] = str(remotename[1]) for remotename in conn.walk('1.0.8802.1.1.2.1.4.1.1.7'): - iname = idxtoifname[remotename[0][-2]] + iname = idxtoifname.get(remotename[0][-2], + idxtoportid[remotename[0][-2]]) _init_lldp(lldpdata, iname, remotename[0][-2], idxtoportid, switch) lldpdata[iname]['peerportid'] = sanitize(remotename[1]) for remoteid in conn.walk('1.0.8802.1.1.2.1.4.1.1.5'): - iname = idxtoifname[remoteid[0][-2]] + iname = idxtoifname.get(remoteid[0][-2], + idxtoportid[remoteid[0][-2]]) _init_lldp(lldpdata, iname, remoteid[0][-2], idxtoportid, switch) lldpdata[iname]['peerchassisid'] = sanitize(remoteid[1]) for entry in lldpdata: diff --git a/confluent_server/confluent/networking/macmap.py b/confluent_server/confluent/networking/macmap.py index 34d9b4fd..894109be 100644 --- a/confluent_server/confluent/networking/macmap.py +++ b/confluent_server/confluent/networking/macmap.py @@ -82,6 +82,8 @@ _blacklistnames = ( def _namesmatch(switchdesc, userdesc): + if switchdesc is None: + return False if switchdesc == userdesc: return True try: From bbb8e50c3e3221337fcd7e23b1b13c0e966b5f0a Mon Sep 17 00:00:00 2001 From: Jarrod Johnson Date: Thu, 11 Mar 2021 16:27:17 -0500 Subject: [PATCH 08/14] Fix configbmc gateway check It erroneously linked to prefix to check gateway or not. --- confluent_osdeploy/genesis/profiles/default/scripts/configbmc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/confluent_osdeploy/genesis/profiles/default/scripts/configbmc b/confluent_osdeploy/genesis/profiles/default/scripts/configbmc index 604b39b2..fb1d61f4 100644 --- a/confluent_osdeploy/genesis/profiles/default/scripts/configbmc +++ b/confluent_osdeploy/genesis/profiles/default/scripts/configbmc @@ -411,7 +411,7 @@ def main(): dotwait() while awaitprefix and not check_subnet(s, bmccfg['prefixv4'], channel): dotwait() - while awaitprefix and not check_gateway(s, bmccfg['bmcgw'], channel): + while awaitgw and not check_gateway(s, bmccfg['bmcgw'], channel): dotwait() sys.stdout.write('done\n') sys.stdout.flush() From ffe0754dd95bae032e511e21614e3809499fb009 Mon Sep 17 00:00:00 2001 From: Jarrod Johnson Date: Fri, 12 Mar 2021 12:42:57 -0500 Subject: [PATCH 09/14] Fix typo in confluent profile.yaml The quiet argument was missed due to typo in parameter name. --- confluent_osdeploy/genesis/profiles/default/profile.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/confluent_osdeploy/genesis/profiles/default/profile.yaml b/confluent_osdeploy/genesis/profiles/default/profile.yaml index bc5d6fb6..7ed4fb92 100644 --- a/confluent_osdeploy/genesis/profiles/default/profile.yaml +++ b/confluent_osdeploy/genesis/profiles/default/profile.yaml @@ -1,2 +1,2 @@ label: Genesis -kernelarags: quiet +kernelargs: quiet From 874947076dcf7e171326d94d23e35d6bb99e6dc4 Mon Sep 17 00:00:00 2001 From: Jarrod Johnson Date: Fri, 12 Mar 2021 13:54:36 -0500 Subject: [PATCH 10/14] Fix local console behavior in genesis This will have the vga console be less concerning. --- .../genesis/initramfs/opt/confluent/bin/rungenesis | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/confluent_osdeploy/genesis/initramfs/opt/confluent/bin/rungenesis b/confluent_osdeploy/genesis/initramfs/opt/confluent/bin/rungenesis index 6f98b9b1..28dfdb79 100644 --- a/confluent_osdeploy/genesis/initramfs/opt/confluent/bin/rungenesis +++ b/confluent_osdeploy/genesis/initramfs/opt/confluent/bin/rungenesis @@ -9,12 +9,13 @@ if ! grep console= /proc/cmdline >& /dev/null; then if [ ! -z "$autocons" ]; then echo "Using $(cat /tmp/01-autocons.conf)" tmux a <> $autocons >&0 2>&1 & + TERM=linux tmux a <> /dev/tty1 >&0 2>&1 & else tmux a <> /dev/console >&0 2>&1 & fi else tmux a <> /dev/console >&0 2>&1 & - tmux a <> /dev/tty1 >&0 2>&1 & + TERM=linux tmux a <> /dev/tty1 >&0 2>&1 & fi echo -n "udevd: " /usr/lib/systemd/systemd-udevd --daemon From 19d4a3a83f191cd70ce8dc01544f17fc71176a5a Mon Sep 17 00:00:00 2001 From: Jarrod Johnson Date: Sat, 13 Mar 2021 12:33:53 -0500 Subject: [PATCH 11/14] Have autocons attempt sizing of serial console If a terminal is open during autocons, that terminal will be the size of the console. Otherwise, fallback to 100x31. --- confluent_osdeploy/utils/autocons.c | 63 +++++++++++++++++++++++++---- 1 file changed, 55 insertions(+), 8 deletions(-) diff --git a/confluent_osdeploy/utils/autocons.c b/confluent_osdeploy/utils/autocons.c index 018f43b5..75389af9 100644 --- a/confluent_osdeploy/utils/autocons.c +++ b/confluent_osdeploy/utils/autocons.c @@ -1,3 +1,4 @@ +#include #include #include #include @@ -20,20 +21,29 @@ int main(int argc, char* argv[]) { struct termios tty; + struct termios tty2; + struct winsize ws; + unsigned width, height; int ttyf; - int spcr; + int tmpi; int currspeed; + int flags; speed_t cspeed; char buff[128]; + int bufflen; + fd_set set; + struct timeval timeout; char* offset; uint64_t address; - spcr = open("/sys/firmware/acpi/tables/SPCR", O_RDONLY); - if (spcr < 0) { + bufflen = 0; + tmpi = open("/sys/firmware/acpi/tables/SPCR", O_RDONLY); + if (tmpi < 0) { exit(0); } - if (read(spcr, buff, 80) < 80) { + if (read(tmpi, buff, 80) < 80) { exit(0); } + close(tmpi); if (buff[8] != 2) exit(0); //revision 2 if (buff[36] != 0) exit(0); //16550 only if (buff[40] != 1) exit(0); //IO only @@ -69,12 +79,49 @@ int main(int argc, char* argv[]) { } tcgetattr(ttyf, &tty); if (cspeed) { - cfsetospeed(&tty, B115200); - cfsetispeed(&tty, B115200); + cfsetospeed(&tty, cspeed); + cfsetispeed(&tty, cspeed); } + printf("%s\n", buff); + tcgetattr(ttyf, &tty2); + cfmakeraw(&tty2); + tcsetattr(ttyf, TCSANOW, &tty2); + flags = fcntl(ttyf, F_GETFL, 0); + fcntl(ttyf, F_SETFL, flags | O_NONBLOCK); + while (read(ttyf, buff, 64) > 0) { + // Drain any pending reads + } + timeout.tv_sec = 0; + timeout.tv_usec = 500000; + FD_ZERO(&set); + FD_SET(ttyf, &set); + write(ttyf, "\0337\033[999;999H\033[6n\0338", 18); + while (select(ttyf + 1, &set, NULL, NULL, &timeout) > 0) { + if ((tmpi = read(ttyf, buff + bufflen, 127 - bufflen)) < 0) { + if (errno == EAGAIN || errno == EWOULDBLOCK) { + continue; + } else { + break; + } + } + bufflen += tmpi; + buff[bufflen] = 0; + if (strchr(buff, 'R')) { + break; + } + } + fcntl(ttyf, F_SETFL, flags); + ws.ws_xpixel = 0; + ws.ws_ypixel = 0; + if (sscanf(buff, "\033[%u;%uR", &height, &width) == 2) { + ws.ws_col = width; + ws.ws_row = height; + } else { + ws.ws_col = 100; + ws.ws_row = 31; + } + ioctl(ttyf, TIOCSWINSZ, &ws); tcsetattr(ttyf, TCSANOW, &tty); ioctl(ttyf, TIOCCONS, 0); - printf("%s\n", buff); - } From 797e197bc7578bb4902813262e98c8dd28dcb4ea Mon Sep 17 00:00:00 2001 From: Jarrod Johnson Date: Sat, 13 Mar 2021 12:47:48 -0500 Subject: [PATCH 12/14] Have tmux keep reattaching If someone accidentally detaches, then intervene and reattach. --- .../genesis/initramfs/opt/confluent/bin/rungenesis | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/confluent_osdeploy/genesis/initramfs/opt/confluent/bin/rungenesis b/confluent_osdeploy/genesis/initramfs/opt/confluent/bin/rungenesis index 28dfdb79..7af33603 100644 --- a/confluent_osdeploy/genesis/initramfs/opt/confluent/bin/rungenesis +++ b/confluent_osdeploy/genesis/initramfs/opt/confluent/bin/rungenesis @@ -8,14 +8,14 @@ if ! grep console= /proc/cmdline >& /dev/null; then echo $autocons > /tmp/01-autocons.devnode if [ ! -z "$autocons" ]; then echo "Using $(cat /tmp/01-autocons.conf)" - tmux a <> $autocons >&0 2>&1 & - TERM=linux tmux a <> /dev/tty1 >&0 2>&1 & + (while :; do tmux a <> $autocons >&0 2>&1; done) & + (while :; do TERM=linux tmux a <> /dev/tty1 >&0 2>&1; done) & else - tmux a <> /dev/console >&0 2>&1 & + (while :; do tmux a <> /dev/console >&0 2>&1; done) & fi else - tmux a <> /dev/console >&0 2>&1 & - TERM=linux tmux a <> /dev/tty1 >&0 2>&1 & + (while :; do tmux a <> /dev/console >&0 2>&1; done) & + (while :; do TERM=linux tmux a <> /dev/tty1 >&0 2>&1; done) & fi echo -n "udevd: " /usr/lib/systemd/systemd-udevd --daemon From cafbc1d1c244e7f0370b37a445336d229c81cdaa Mon Sep 17 00:00:00 2001 From: Jarrod Johnson Date: Sat, 13 Mar 2021 12:49:26 -0500 Subject: [PATCH 13/14] Have tty2 also run a shell Some may find switching VTs to be more intuitive than tmux session management. Provide one extra on tty2 for such a scenario. --- .../genesis/initramfs/opt/confluent/bin/rungenesis | 1 + 1 file changed, 1 insertion(+) diff --git a/confluent_osdeploy/genesis/initramfs/opt/confluent/bin/rungenesis b/confluent_osdeploy/genesis/initramfs/opt/confluent/bin/rungenesis index 7af33603..7795ba22 100644 --- a/confluent_osdeploy/genesis/initramfs/opt/confluent/bin/rungenesis +++ b/confluent_osdeploy/genesis/initramfs/opt/confluent/bin/rungenesis @@ -17,6 +17,7 @@ else (while :; do tmux a <> /dev/console >&0 2>&1; done) & (while :; do TERM=linux tmux a <> /dev/tty1 >&0 2>&1; done) & fi +(while :; do TERM=linux tmux <> /dev/tty2 >&0 2>&1; done) & echo -n "udevd: " /usr/lib/systemd/systemd-udevd --daemon echo -n "Loading drivers..." From e40c3627432726c22859e7a27bb965d664fe3ae4 Mon Sep 17 00:00:00 2001 From: Jarrod Johnson Date: Tue, 16 Mar 2021 14:53:55 -0400 Subject: [PATCH 14/14] Fix network configuration changes through collective --- confluent_server/confluent/messages.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/confluent_server/confluent/messages.py b/confluent_server/confluent/messages.py index 2f6ab998..76f5a706 100644 --- a/confluent_server/confluent/messages.py +++ b/confluent_server/confluent/messages.py @@ -1054,7 +1054,7 @@ class InputNetworkConfiguration(ConfluentInputMessage): if 'ipv4_gateway' not in inputdata: inputdata['ipv4_gateway'] = None - if 'ipv4_configuration' in inputdata: + if 'ipv4_configuration' in inputdata and inputdata['ipv4_configuration']: if inputdata['ipv4_configuration'].lower() not in ['dhcp','static']: raise exc.InvalidArgumentException( 'Unrecognized ipv4_configuration')