@@ -50,6 +50,8 @@
#include <netinet/tcp.h>
#include <unistd.h>
#include <semaphore.h>
+#include <ctype.h>
+#include <stdlib.h>
#include <rdma/rdma_cma.h>
#include <rdma/rdma_verbs.h>
@@ -122,6 +124,217 @@ struct fd_info {
atomic_t refcnt;
};
+typedef struct {
+ char *name;
+ uint32_t domain;
+ uint32_t type;
+ uint32_t protocol;
+} config_entry_t;
+
+static config_entry_t *entryp;
+static int16_t nentries;
+static int16_t config_avail;
+extern char *program_invocation_short_name;
+
+/* scan preload configuration file and create
+ * in-memory config store
+ * should be called only once under lock
+ */
+static int scan_preload_config(void)
+{
+ FILE *fp;
+ char line[512];
+ char *lp, *cp, *str1, *str2;
+ char *token, *subtoken, *saveptr1, *saveptr2;
+ int i, j, ret = 0;
+
+ fp = fopen(RS_CONF_DIR "/preload_config", "r");
+ if (fp == NULL) {
+ return -1;
+ }
+
+ while ((lp = fgets(line, sizeof(line), fp)) != NULL) {
+
+ /* trim white space at the beginning of each line */
+ while (*lp != '\0') {
+ if (isspace(*lp)) {
+ lp++;
+ continue;
+ } else {
+ break;
+ }
+ }
+
+ /* skip comment and blank lines */
+ if (*lp == '\0' || *lp == '#') {
+ continue;
+ }
+
+ /* trim comments and newlines at the end of each line */
+ if ((cp = strpbrk(lp, "#\n")) != NULL) {
+ *cp = '\0';
+ }
+
+ /* now allocate memory for new configuration entry */
+ entryp = (config_entry_t *) realloc(entryp, (nentries +
1) *
+ sizeof(config_entry_t));
+ if (!entryp) {
+ ret = -1;
+ goto scan_done;
+ }
+ memset(entryp + nentries, '\0', sizeof(config_entry_t));
+
+ /* tokenize the retrieved line and parse individual
fields */
+ for (i = 1, str1 = lp; ; i++, str1 = NULL) {
+ token = strtok_r(str1, " \t", &saveptr1);
+ if (token == NULL) {
+ break;
+ }
+
+ /* first field should contain program name */
+ if (i == 1) {
+ entryp[nentries].name = (char *)
malloc((strlen(token) + 1));
+ if (!entryp[nentries].name) {
+ ret = -1;
+ goto scan_done;
+ }
+ memcpy(entryp[nentries].name, token,
strlen(token) + 1);
+ continue;
+ }
+
+ /* second field onwards can contain multiple
entries
+ * separated by commas
+ */
+ for (j = 1, str2 = token; ; j++, str2 = NULL) {
+ subtoken = strtok_r(str2, ",",
&saveptr2);
+ if (subtoken == NULL) {
+ break;
+ }
+
+ /* second field is socket domain
+ * rsocket currently recognizes only
AF_INET, AF_INET6
+ * and AF_IB domains
+ * '*' implies all the valid domains
+ */
+ if (i == 2) {
+ if (*subtoken == '*') {
+ entryp[nentries].domain
|= (1 << AF_INET);
+ entryp[nentries].domain
|= (1 << AF_INET6);
+ entryp[nentries].domain
|= (1 << AF_IB);
+ break;
+ } else if (strcmp(subtoken,
"inet6") == 0) {
+ entryp[nentries].domain
|= (1 << AF_INET6);
+ } else if (strcmp(subtoken,
"inet") == 0) {
+ entryp[nentries].domain
|= (1 << AF_INET);
+ } else if (strcmp(subtoken,
"ib") == 0) {
+ entryp[nentries].domain
|= (1 << AF_IB);
+ }
+ continue;
+ }
+
+ /* third field is socket type
+ * rsocket currently recognizes only
SOCK_STREAM and
+ * SOCK_DGRAM types
+ * '*' implies all the valid types
+ */
+ if (i == 3) {
+ if (*subtoken == '*') {
+ entryp[nentries].type |=
(1 << SOCK_STREAM);
+ entryp[nentries].type |=
(1 << SOCK_DGRAM);
+ break;
+ } else if (strcmp(subtoken,
"stream") == 0) {
+ entryp[nentries].type |=
(1 << SOCK_STREAM);
+ } else if (strcmp(subtoken,
"dgram") == 0) {
+ entryp[nentries].type |=
(1 << SOCK_DGRAM);
+ }
+ continue;
+ }
+
+ /* fourth field is socket protocol
+ * rsocket currently recgonizes only
IPPROTO_TCP and
+ * IPPROTO_UDP protocols
+ * '*' implies all the valid protocols
+ */
+ if (i == 4) {
+ if (*subtoken == '*') {
+
entryp[nentries].protocol |= (1 << IPPROTO_TCP);
+
entryp[nentries].protocol |= (1 << IPPROTO_UDP);
+ break;
+ } else if (strcmp(subtoken,
"tcp") == 0) {
+
entryp[nentries].protocol |= (1 << IPPROTO_TCP);
+ } else if (strcmp(subtoken,
"udp") == 0) {
+
entryp[nentries].protocol |= (1 << IPPROTO_UDP);
+ }
+ continue;
+ }
+ }
+ }
+ nentries += 1;
+ }
+
+scan_done:
+ fclose(fp);
+ return ret;
+}
+
+/* free in-memory config store
+ * should be called only once during finalization
+ */
+static void free_preload_config(void)
+{
+ int i;
+
+ if (entryp) {
+ for (i = 0; i < nentries; i++) {
+ if (entryp[i].name) {
+ free(entryp[i].name);
+ }
+ }
+ free(entryp);
+ }
+
+ return;
+}
+
+/* check whether interception is required for this socket
+ * compares the provided attributes with that available in the
in-memory
+ * data store for the current process
+ * sets-up in-memory config store if it's already not done
+ */
+static int intercept_socket(int domain, int type, int protocol)
+{
+ int i;
+
+ /* locate the config entry */
+ for (i = 0; i < nentries; i++) {