/* Author(s): Amnon Shiloh and Oren Laadan for Mosix */ /* Code derived from previous work by Amnon Shiloh and Oren Laadan. */ /* Adapted to OpenMosix from Mosix and bugfixing by David Santo Orcero */ /* irbis@orcero.org http://www.orcero.org/irbis */ /* Mosix is (c) of prof. Amnon Barak http://www.mosix.org */ /* Original code is (c) of prof. Amnon Barak http://www.mosix.org */ /* OpenMosix is (c) of Moshe Bar http://www.openmosix.com */ /* Each respective trademark is of its own owner */ /* All rights reserved. */ /* This software is distributed under GPL 2 */ /* THIS SOFTWARE IS PROVIDED "AS IS". NO WARRANTY IS ASSUMED. */ /* NO LIABILITY OF ANY KIND FOR ANY DAMAGES WHATSOEVER RESULTING */ /* FROM THE USE OF THIS SOFTWARE WILL BE ACCEPTED. IT CAN BURN */ /* YOUR HARD DISK, ERASE ALL YOUR DATA AND BROKE DOWN YOUR */ /* MICROWAVE OVEN. YOU ARE ADVISED. */ /* THIS SOFTWARE IS PROVIDED IN ITS "AS IS" CONDITION, WITH NO WARRANTY */ /* WHATSOEVER. NO LIABILITY OF ANY KIND FOR ANY DAMAGES WHATSOEVER RESULTING*/ /* FROM THE USE OF THIS SOFTWARE WILL BE ACCEPTED. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #define ERR_OK 0 #define ERR_PROG 1 #define ERR_PROG_PID 3 #define ERR_OTHER 102 char *pname; int proc_mosix_admin_config_fd; int proc_mosix_admin_mospe_fd; struct mosixnet mosnet[MAX_MOSNET_ENTS+1]; char hostnamebuf[MAXHOSTNAMELEN + 1]; char check; char two_phase = -1; void not_mosix() { fprintf(stderr,"Error: this is not OpenMosix!\n"); exit(ERR_OTHER); } void usage(void); int table_read(int *pe, int *ready_pe, int *nents, struct mosixnet *mosnet); void setpe_off(void); void setpe_read(FILE *); void setpe_write(FILE *, int, int); void set_gateways(int); int write_file(int, struct mosixnet *, int); void ip_display(int, FILE *); void ip_setpe(int, FILE *); void ip_check_table(int, int); int ip_need_two_phase(int, int, int, struct mosixnet *, int); #define GATEWAYS_FILENAME "/proc/hpc/admin/gateways" #define CONFIG_FILENAME "/proc/hpc/admin/config" #define MOSPE_FILENAME "/proc/hpc/admin/mospe" int main(int c, char *v[]) { int pe = 0; int opt; int net_type = AF_INET; const char *filename = "-"; FILE *table; int write = -1; int gateways = -1; int off = 0; pname = v[0]; for (opt = strlen(pname); opt--; ) if (pname[opt] == '/') { pname += opt + 1; break; } while ((opt = getopt(c, v, "f:g:n:o:p:crwW")) != EOF) { if (off) usage(); switch (opt) { case 'o': if (!optarg || strcmp(optarg, "ff")) usage(); off = 1; write = 1; break; case 'n': if (!optarg || write == 0) usage(); write = 1; if (!strcmp(optarg, "inet")) break; usage(); case 'p': if (!optarg || write == 0) usage(); write = 1; if (!(pe = atoi(optarg))) { fprintf(stderr, "%s: Invalid node " "number\n", pname); } break; case 'f': if(!optarg) usage(); filename = optarg; break; case 'c': if (write == 0) usage(); write = 1; check = 1; break; case 'g': if(!optarg || gateways != -1 || sscanf(optarg, "%d%c", &gateways, (char *)&gateways) != 1 || gateways < 0 || gateways > 2) usage(); break; case 'w': if (write == 0 || two_phase == 1) usage(); write = 1; two_phase = 0; break; case 'W': if (write == 0 || two_phase == 0) usage(); write = 1; two_phase = 1; break; case 'r': if (write == 1) usage(); write = 0; break; default: usage(); } } if (optind < c) usage(); if (write == -1) usage(); if (!strcmp(filename, "-")) table = (write ? stdin : stdout); else if (!(table = fopen(filename, write ? "r" : "w"))) { perror(filename); exit(ERR_OTHER); } proc_mosix_admin_mospe_fd = open(MOSPE_FILENAME, write ? O_RDWR : O_RDONLY); proc_mosix_admin_config_fd = open(CONFIG_FILENAME, write ? O_RDWR : O_RDONLY); if (proc_mosix_admin_mospe_fd < 0 || proc_mosix_admin_config_fd < 0) not_mosix(); if (off) setpe_off(); else if (write) setpe_write(table, pe, net_type); else setpe_read(table); if(gateways != -1) set_gateways(gateways); exit (ERR_OK); } void setpe_off(void) { if(write(proc_mosix_admin_mospe_fd, "0", 1) == 1) return; perror("unconfiguring OpenMosix"); exit(ERR_OTHER); } int table_read(int *pe, int *pe_ready, int *nents, struct mosixnet *mosnet) { int i, j, error; char str[20]; error = read(proc_mosix_admin_mospe_fd, str, 20); if (error < 0) { if (errno == ENOSYS) return (errno); perror("read"); exit(ERR_OTHER); } *pe = atoi(str); if (!(*pe)) { *nents = *pe = 0; return(0); } for (i = 0, j = 0; i < error; i++) if (str[i] == '(') { j = i + 1; str[i] = '\0'; } else if (str[i] == ')') str[i] = '\0'; if (j) *pe_ready = atoi(str + j); else *pe_ready = 0; error = read(proc_mosix_admin_config_fd, (char *) mosnet, sizeof(struct mosixnet) * MAX_MOSNET_ENTS); if (error < 0) { perror("read"); exit(ERR_OTHER); } *nents = error / sizeof(struct mosixnet); return (0); } void setpe_read(FILE *table) { int pe, pe_ready = -1; int error; int net, nents; error = table_read(&pe, &pe_ready, &nents, mosnet); if (error) { perror(""); exit(ERR_OTHER); } if (!pe) { fprintf(table, "OpenMosix is currently disabled\n"); exit(ERR_PROG_PID); } fprintf(table, "This is OpenMosix node #%d", pe); if (pe_ready > 0) fprintf(table, " (PE already set to %d)", pe_ready); fprintf(table, "\n"); net = mosnet[0].saddr.sa_family; switch (net) { case AF_INET: ip_display(nents, table); break; default: fprintf(stderr, "%s: severe problem ! unknown network " "type %d\n", pname, net); exit(ERR_OTHER); } } void setpe_write(FILE *table, int pe, int net_type) { switch (net_type) { case AF_INET: ip_setpe(pe, table); break; default: fprintf(stderr, "%s: unknown network type %d\n", pname, net_type); exit(ERR_OTHER); } } int write_file(int pe, struct mosixnet *table, int nent) { int error; char str[10]; sprintf(str, "%d", pe); error = write(proc_mosix_admin_mospe_fd, str, strlen(str) + 1); if (error < 0) { perror("The OpenMosix kernel refused to accept the node-number"); exit(ERR_PROG); } nent *= sizeof(struct mosixnet); error = write(proc_mosix_admin_config_fd, (char*) table, (size_t) nent); if (error < 0) { perror("The OpenMosix kernel refused to accept the table"); return (-1); } return (0); } #define NET_TO_IP(t) (((struct sockaddr_in *) &(t).saddr)->sin_addr.s_addr) void ip_display(int nents, FILE *table) { struct hostent *hostent; u_long ipaddr; int i, n = 0, a = 0; char host[512]; fprintf(table, "Network protocol: %d (AF_INET)\n", AF_INET); for (i = 0; i < nents; i++) { ipaddr = NET_TO_IP(mosnet[i]); if (mosnet[i].cnt && (hostent = gethostbyaddr((char *) &ipaddr, 4, AF_INET))) strcpy(host, hostent->h_name); else { unsigned int a = (ipaddr) & 0xff; unsigned int b = (ipaddr >> 8) & 0xff; unsigned int c = (ipaddr >> 16) & 0xff; unsigned int d = (ipaddr >> 24); sprintf(host, "%d.%d.%d.%d", a, b, c, d); } if(mosnet[i].cnt) { fprintf(table, "OpenMosix range %5d-%-5d begins at %s\n", mosnet[i].base, mosnet[i].base+mosnet[i].cnt-1, host); n += mosnet[i].cnt; } else { fprintf(table, "Node %d has an alias: %s\n", mosnet[i].base, host); a++; } } fprintf(table, "Total configured: %d", n); if(a) fprintf(table, "; %d alias%s", a, a > 1 ? "es" : ""); fprintf(table, "\n"); exit(ERR_OK); } void ip_setpe(int pe, FILE *table) { char hostname[MAXHOSTNAMELEN + 1]; struct hostent *hostent; u_long myaddr, ipaddr; int err, n = 0; char buf[513], host[512]; unsigned int a, b, c, d; struct mosixnet oldmosnet[MAX_MOSNET_ENTS]; int oldpe, oldready_pe, oldnents; char word[10]; while(fgets(buf, 512, table)) if(buf[0] && buf[0] != '#' && buf[0] != '\n') { buf[512] = '\0'; if (sscanf(buf, "%d %d.%d.%d.%d %d", &mosnet[n].base, &a, &b, &c, &d, &mosnet[n].cnt) == 6) { ip_line: NET_TO_IP(mosnet[n++]) = (a<<24) | (b<<16) | (c<<8) | d; check_cnt: if(mosnet[n].cnt < 0) { fprintf(stderr, "%s: Negative count\n", pname); exit(ERR_OTHER); } if(n > MAX_MOSNET_ENTS) { fprintf(stderr, "%s: Table Overflow\n", pname); exit(ERR_OTHER); } } else if (sscanf(buf, "%d %s %d", &mosnet[n].base, host, &mosnet[n].cnt) == 3) { host_line: if ((hostent = gethostbyname(host)) == NULL) { if ((ipaddr = inet_addr(host)) == -1) { herror(host); exit(ERR_OTHER); } } else { bcopy(hostent->h_addr, &ipaddr, sizeof(ipaddr)); ipaddr = ntohl(ipaddr); } NET_TO_IP(mosnet[n++]) = ipaddr; goto check_cnt; } else if (sscanf(buf, "%d %d.%d.%d.%d %10s", &mosnet[n].base, &a, &b, &c, &d, word) == 6 && !strcasecmp(word, "alias")) { mosnet[n].cnt = 0; goto ip_line; } else if (sscanf(buf, "%d %s %10s", &mosnet[n].base, host, word) == 3 && !strcasecmp(word, "alias")) { mosnet[n].cnt = 0; goto host_line; } else { if (buf[strlen(buf)-1] == '\n') buf[strlen(buf)-1] = '\0'; fprintf(stderr, "Bad Table Input: <%s>\n", buf); exit(ERR_OTHER); } } if (!n) { fprintf(stderr, "%s: the table is empty.\n", pname); exit(ERR_OTHER); } if (!pe) { hostname[MAXHOSTNAMELEN] = '\0'; if (gethostname(hostname, MAXHOSTNAMELEN) < 0) { perror("setpe: gethostname"); exit(ERR_OTHER); } if ((hostent = gethostbyname(hostname)) == NULL) { if ((myaddr = inet_addr(hostname)) == -1) { herror(hostname); exit(ERR_OTHER); } } else { bcopy(hostent->h_addr, &myaddr, sizeof(myaddr)); myaddr = ntohl(myaddr); } for (a = 0 ; a < n ; a++) if (myaddr >= NET_TO_IP(mosnet[a]) && myaddr < NET_TO_IP(mosnet[a]) + mosnet[a].cnt) break; if (a == n) { fprintf(stderr, "%s: the supplied table is well-" "formatted,\n", pname); fprintf(stderr, "but my IP address (%d.%d.%d.%d) " "is not there!\n", (unsigned int)(myaddr >> 24), (unsigned int)((myaddr >> 16) & 0xff), (unsigned int)((myaddr >> 8) & 0xff), (unsigned int)(myaddr & 0xff)); exit(ERR_OTHER); } pe = mosnet[a].base + myaddr - NET_TO_IP(mosnet[a]); } ip_check_table(n, pe); /* set network family - should be in the first entry */ mosnet[0].saddr.sa_family = AF_INET; /* lastly, the kernel expects network order for the IP's */ for (a = 0; a < n; a++) NET_TO_IP(mosnet[a]) = htonl(NET_TO_IP(mosnet[a])); if ((err = table_read(&oldpe, &oldready_pe, &oldnents, oldmosnet))) { if (err != ENOSYS) { perror(""); exit(ERR_OTHER); } /* else: silently ignore... we not configured anyway */ } if(!err) { if(ip_need_two_phase(pe, n, oldpe, oldmosnet, oldnents)) { if(!two_phase) { fprintf(stderr, "%s: The proposed change will modify the current node's mapping,\n", pname); fprintf(stderr, "requiring a full OpenMosix restart, including bringing all processes back home:\n"); fprintf(stderr, "If you are sure about the change, use 'setpe -W' (instead of 'setpe -w').\n"); exit(ERR_OTHER); }; }; } else { two_phase = 0; }; if (check) return; /* -- COMMIT POINT -- */ close(proc_mosix_admin_mospe_fd); close(proc_mosix_admin_config_fd); proc_mosix_admin_mospe_fd = open(MOSPE_FILENAME, O_WRONLY); proc_mosix_admin_config_fd = open(CONFIG_FILENAME, O_WRONLY); if (two_phase) { /* ok then, so - shutdown and try new configuration, and if failed - restore old one */ setpe_off(); close(proc_mosix_admin_mospe_fd); proc_mosix_admin_mospe_fd = open(MOSPE_FILENAME, O_WRONLY); } if (write_file(pe, mosnet, n) == -1 && two_phase) { /* FAILED */ close(proc_mosix_admin_mospe_fd); close(proc_mosix_admin_config_fd); proc_mosix_admin_mospe_fd = open(MOSPE_FILENAME, O_WRONLY); proc_mosix_admin_config_fd = open(CONFIG_FILENAME, O_WRONLY); (void) write_file(oldpe, oldmosnet, oldnents); fprintf(stderr, "%s: configuration restored!\n", pname); } } void ip_check_table(int n, int pe) { register int i, j; register struct mosixnet *t, *q; char foundme = 0; int aok; if (pe < 1) { fprintf(stderr, "%s: My node number < 1 ???\n", pname); exit(ERR_OTHER); } if (pe >= MOSIX_MAX) { fprintf(stderr, "%s: This node number is larger than" "the maximum (%d)\n", pname, MOSIX_MAX-1); exit(ERR_OTHER); } if (n < 1) { fprintf(stderr, "%s: The table is Empty!\n", pname); exit(ERR_OTHER); } if (n > MAX_MOSNET_ENTS) { fprintf(stderr, "%s: Table size too big (max %d entries)\n", pname, MAX_MOSNET_ENTS); exit(ERR_OTHER); } for(t = mosnet , i = 0 ; i < n ; i++ , t++) { if (t->cnt < 0) { fprintf(stderr, "%s: Table contains a range with a negative " "number of nodes!\n", pname); exit(ERR_OTHER); } if (t->base < 1) { fprintf(stderr, "%s: Table contains OpenMosix 'node-#%d'!\n", pname, t->base); exit(ERR_OTHER); } if (t->base + t->cnt - 1 >= MOSIX_MAX) { fprintf(stderr, "%s: Table contains node-#%d (max=%d)!\n", pname, t->base + t->cnt - 1, MOSIX_MAX - 1); exit(ERR_OTHER); } if (NET_TO_IP(*t) + t->cnt < NET_TO_IP(*t)) { fprintf(stderr, "%s: Table contains an IP Address(es) Wrap!\n", pname); exit(ERR_OTHER); } if(t->cnt) { for (q = mosnet , j = 0 ; j < i ; j++ , q++) if(q->cnt) { if ((q->base < t->base && q->base + q->cnt > t->base) || (q->base >= t->base && q->base < t->base+t->cnt)) { fprintf(stderr, "%s: Table contains conflicting" " OpenMosix addresses!\n", pname); exit(ERR_OTHER); } if ((NET_TO_IP(*q) < NET_TO_IP(*t) && NET_TO_IP(*q) + q->cnt > NET_TO_IP(*t)) || (NET_TO_IP(*q) >= NET_TO_IP(*t) && NET_TO_IP(*q) < NET_TO_IP(*t) + t->cnt)) { fprintf(stderr, "%s: Table contains conflicting" " IP addresses!\n", pname); exit(ERR_OTHER); } } if (pe >= t->base && pe < t->base + t->cnt) foundme = 1; } else { aok = 0; for (q = mosnet , j = 0 ; j < n ; j++ , q++) if(j == i) continue; else if(q->cnt) { if (t->base >= q->base && t->base < q->base + q->cnt) aok = 1; if ((NET_TO_IP(*t) >= NET_TO_IP(*q) && NET_TO_IP(*t) < NET_TO_IP(*q) + q->cnt)) { fprintf(stderr, "%s: Table contains an IP " "conflict between a range and an alias!" "\n", pname); exit(ERR_OTHER); } } else if(NET_TO_IP(*t) == NET_TO_IP(*q)) { fprintf(stderr, "%s: Table contains a conflict: 2 or " "more aliases claim the same IP address!\n", pname); exit(ERR_OTHER); } if(!aok) { fprintf(stderr, "%s: Table contains an alias for node " "#%d - which is not included!\n", pname, t->base); exit(ERR_OTHER); } } } if (!foundme) { fprintf(stderr, "%s: the table is ok, but I'm not there!\n", pname); exit(ERR_OTHER); } } int ip_need_two_phase(int pe, int nents, int oldpe, struct mosixnet *oldmosnet, int oldnents) { register int i; register struct mosixnet *t; u_long ip = 0, oldip = 0; /* * sufficient conditions for two phases: * (1) pe != oldpe (but: oldpe != 0, not startup, * pe != 0, not shutdown) * (2) ip != oldip */ if (!pe || !oldpe) return (0); if (pe != oldpe) return (1); /* find the ip's */ for(t = mosnet, i = 0; i < nents ; i++ , t++) { if (pe >= t->base && pe < t->base + t->cnt) ip = NET_TO_IP(*t) + pe - t->base; } for(t = oldmosnet, i = 0; i < oldnents ; i++ , t++) { if (oldpe >= t->base && oldpe < t->base + t->cnt) oldip = NET_TO_IP(*t) + oldpe - t->base; } if (!ip || !oldip) { fprintf(stderr, "%s: new IP or old IP is 0.0.0.0 ?!\n", pname); exit(ERR_OTHER); } if (ip != oldip) return (1); return (0); } void set_gateways(int gateways) { char str[10]; int fd; if((fd = open(GATEWAYS_FILENAME, O_RDWR)) < 0) { fprintf(stderr, "%s: Error - this version of OpenMosix does not" " support the '-g' option!\n", pname); exit(ERR_OTHER); } sprintf(str, "%d", gateways); if (write(fd, str, strlen(str) + 1) < 0) { perror("writing the '-g' value"); exit(ERR_OTHER); } close(fd); } void usage() { fprintf(stderr, "OpenMosix's setpe usage: %s -[w|W] [-n inet] [-c] [-p pe] [-g {0|1|2}]" " [-f filename|-]\n" " or: %s -r [-f filename|-]\n" " or: %s -off\n", pname, pname, pname); exit(ERR_OK); }