You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@trafficserver.apache.org by zw...@apache.org on 2014/04/20 21:20:24 UTC
[07/50] [abbrv] TS-2637: add traffic_line records match option
http://git-wip-us.apache.org/repos/asf/trafficserver/blob/0389be39/mgmt/api/NetworkUtilsRemote.cc
----------------------------------------------------------------------
diff --git a/mgmt/api/NetworkUtilsRemote.cc b/mgmt/api/NetworkUtilsRemote.cc
index 3bf941a..da4c9ab 100644
--- a/mgmt/api/NetworkUtilsRemote.cc
+++ b/mgmt/api/NetworkUtilsRemote.cc
@@ -61,7 +61,6 @@ extern TSInitOptionT ts_init_options;
/**********************************************************************
* Socket Helper Functions
**********************************************************************/
-
void
set_socket_paths(const char *path)
{
@@ -773,32 +772,25 @@ send_file_write_request(int fd, TSFileNameT file, int ver, int size, char *text)
return err;
}
-/**********************************************************************
- * send_record_get_request
- *
- * purpose: sends request to get record value from Traffic Manager
- * input: fd - file descriptor to use
- * rec_name - name of record to retrieve value for
- * output: TS_ERR_xx
- * format: RECORD_GET <msg_len> <rec_name>
- **********************************************************************/
-TSError
-send_record_get_request(int fd, char *rec_name)
+static TSError
+send_record_get_x_request(OpType optype, int fd, const char *rec_name)
{
char *msg_buf;
int msg_pos = 0, total_len;
- int16_t op;
+ int16_t op = (int16_t)optype;
int32_t msg_len;
TSError err;
- if (!rec_name)
+ ink_assert(op == RECORD_GET || op == RECORD_MATCH_GET);
+
+ if (!rec_name) {
return TS_ERR_PARAMS;
+ }
total_len = SIZE_OP_T + SIZE_LEN + strlen(rec_name);
msg_buf = (char *)ats_malloc(sizeof(char) * total_len);
// fill in op type
- op = (int16_t) RECORD_GET;
memcpy(msg_buf + msg_pos, (void *) &op, SIZE_OP_T);
msg_pos += SIZE_OP_T;
@@ -816,6 +808,35 @@ send_record_get_request(int fd, char *rec_name)
return err;
}
+/**********************************************************************
+ * send_record_get_request
+ *
+ * purpose: sends request to get record value from Traffic Manager
+ * input: fd - file descriptor to use
+ * rec_name - name of record to retrieve value for
+ * output: TS_ERR_xx
+ * format: RECORD_GET <msg_len> <rec_name>
+ **********************************************************************/
+TSError
+send_record_get_request(int fd, const char *rec_name)
+{
+ return send_record_get_x_request(RECORD_GET, fd, rec_name);
+}
+
+/**********************************************************************
+ * send_record_match_request
+ *
+ * purpose: sends request to get a list of matching record values from Traffic Manager
+ * input: fd - file descriptor to use
+ * rec_name - regex to match against record names
+ * output: TS_ERR_xx
+ * format: sequence of RECORD_GET <msg_len> <rec_name>
+ **********************************************************************/
+TSError
+send_record_match_request(int fd, const char *rec_regex)
+{
+ return send_record_get_x_request(RECORD_MATCH_GET, fd, rec_regex);
+}
/*------ control functions -------------------------------------------*/
/**********************************************************************
@@ -1231,19 +1252,25 @@ parse_file_read_reply(int fd, int *ver, int *size, char **text)
* rec_value - the value of the record in string format
* output: errors on error or fill up class with response &
* return SUCC
- * notes: reply format = <TSError> <val_size> <rec_type> <record_value>
+ * notes: reply format = <TSError> <val_size> <name_size> <rec_type> <record_value> <record_name>
+ * Zero-length values and names are supported. If the size field is 0, the corresponding
+ * value field is not transmitted.
* It's the responsibility of the calling function to conver the rec_value
* based on the rec_type!!
**********************************************************************/
TSError
-parse_record_get_reply(int fd, TSRecordT * rec_type, void **rec_val)
+parse_record_get_reply(int fd, TSRecordT * rec_type, void **rec_val, char **rec_name)
{
int16_t ret_val, rec_t;
- int32_t rec_size;
+ int32_t val_size, name_size;
TSError err_t;
- if (!rec_type || !rec_val)
+ if (!rec_type || !rec_val) {
return TS_ERR_PARAMS;
+ }
+
+ *rec_name = NULL;
+ *rec_val = NULL;
// check to see if anything to read; wait for specified time
if (socket_read_timeout(fd, MAX_TIME_WAIT, 0) <= 0) { //time expired before ready to read
@@ -1253,49 +1280,72 @@ parse_record_get_reply(int fd, TSRecordT * rec_type, void **rec_val)
// get the return value (TSError type)
err_t = socket_read_conn(fd, (uint8_t *)&ret_val, SIZE_ERR_T);
if (err_t != TS_ERR_OKAY) {
- return err_t;
+ goto fail;
}
// if !TS_ERR_OKAY, stop reading rest of msg
err_t = (TSError) ret_val;
if (err_t != TS_ERR_OKAY) {
- return err_t;
+ goto fail;
}
// now get size of record_value
- err_t = socket_read_conn(fd, (uint8_t *)&rec_size, SIZE_LEN);
+ err_t = socket_read_conn(fd, (uint8_t *)&val_size, SIZE_LEN);
if (err_t != TS_ERR_OKAY) {
- return err_t;
+ goto fail;
+ }
+
+ // now get size of record name
+ err_t = socket_read_conn(fd, (uint8_t *)&name_size, SIZE_LEN);
+ if (err_t != TS_ERR_OKAY) {
+ goto fail;
}
// get the record type
err_t = socket_read_conn(fd, (uint8_t *)&rec_t, SIZE_REC_T);
if (err_t != TS_ERR_OKAY) {
- return err_t;
+ goto fail;
}
*rec_type = (TSRecordT) rec_t;
- // get record value
- // allocate correct amount of memory for record value
- if (*rec_type == TS_REC_STRING) {
- *rec_val = ats_malloc(sizeof(char) * (rec_size + 1));
- } else {
- *rec_val = ats_malloc(sizeof(char) * (rec_size));
- }
+ // get record value (if there is one)
+ if (val_size) {
+ if (*rec_type == TS_REC_STRING) {
+ *rec_val = ats_malloc(sizeof(char) * (val_size + 1));
+ } else {
+ *rec_val = ats_malloc(sizeof(char) * (val_size));
+ }
- err_t = socket_read_conn(fd, (uint8_t *)(*rec_val), rec_size);
- if (err_t != TS_ERR_OKAY) {
- ats_free(*rec_val);
- *rec_val = NULL;
- return err_t;
+ err_t = socket_read_conn(fd, (uint8_t *)(*rec_val), val_size);
+ if (err_t != TS_ERR_OKAY) {
+ goto fail;
+ }
+
+ // add end of string to end of the record value
+ if (*rec_type == TS_REC_STRING) {
+ ((char *) (*rec_val))[val_size] = '\0';
+ }
}
- // add end of string to end of the record value
- if (*rec_type == TS_REC_STRING) {
- ((char *) (*rec_val))[rec_size] = '\0';
+ // get the record name (if there is one)
+ if (name_size) {
+ *rec_name = (char *)ats_malloc(sizeof(char) * (name_size + 1));
+ err_t = socket_read_conn(fd, (uint8_t *)(*rec_name), name_size);
+ if (err_t != TS_ERR_OKAY) {
+ goto fail;
+ }
+
+ (*rec_name)[name_size] = '\0';
}
+ return TS_ERR_OKAY;
+
+fail:
+ ats_free(*rec_val);
+ ats_free(*rec_name);
+ *rec_val = NULL;
+ *rec_name = NULL;
return err_t;
}
http://git-wip-us.apache.org/repos/asf/trafficserver/blob/0389be39/mgmt/api/NetworkUtilsRemote.h
----------------------------------------------------------------------
diff --git a/mgmt/api/NetworkUtilsRemote.h b/mgmt/api/NetworkUtilsRemote.h
index b30ac14..f251dc0 100644
--- a/mgmt/api/NetworkUtilsRemote.h
+++ b/mgmt/api/NetworkUtilsRemote.h
@@ -76,7 +76,8 @@ TSError send_request_bool(int fd, OpType op, bool flag);
TSError send_file_read_request(int fd, TSFileNameT file);
TSError send_file_write_request(int fd, TSFileNameT file, int ver, int size, char *text);
-TSError send_record_get_request(int fd, char *rec_name);
+TSError send_record_get_request(int fd, const char *rec_name);
+TSError send_record_match_request(int fd, const char *rec_regex);
TSError send_proxy_state_set_request(int fd, TSProxyStateT state, TSCacheClearT clear);
@@ -93,7 +94,7 @@ TSError parse_reply_list(int fd, char **list);
TSError parse_file_read_reply(int fd, int *version, int *size, char **text);
-TSError parse_record_get_reply(int fd, TSRecordT * rec_type, void **rec_val);
+TSError parse_record_get_reply(int fd, TSRecordT * rec_type, void **rec_val, char **rec_name);
TSError parse_record_set_reply(int fd, TSActionNeedT * action_need);
TSError parse_proxy_state_get_reply(int fd, TSProxyStateT * state);
http://git-wip-us.apache.org/repos/asf/trafficserver/blob/0389be39/mgmt/api/TSControlMain.cc
----------------------------------------------------------------------
diff --git a/mgmt/api/TSControlMain.cc b/mgmt/api/TSControlMain.cc
index c507f5b..950e3b5 100644
--- a/mgmt/api/TSControlMain.cc
+++ b/mgmt/api/TSControlMain.cc
@@ -210,198 +210,83 @@ ts_ctrl_main(void *arg)
con_entry = ink_hash_table_iterator_next(accepted_con, &con_state);
continue;
}
+
// determine which handler function to call based on operation
switch (op_t) {
case RECORD_GET:
ret = handle_record_get(client_entry->sock_info, req);
- ats_free(req); // free memory for req
- if (ret == TS_ERR_NET_WRITE || ret == TS_ERR_NET_EOF) {
- Debug("ts_main", "[ts_ctrl_main] ERROR:handle_record_get\n");
- remove_client(client_entry, accepted_con);
- con_entry = ink_hash_table_iterator_next(accepted_con, &con_state);
- continue;
- }
+ break;
+
+ case RECORD_MATCH_GET:
+ ret = handle_record_match(client_entry->sock_info, req);
+ // XXX
break;
case RECORD_SET:
ret = handle_record_set(client_entry->sock_info, req);
- ats_free(req);
- if (ret == TS_ERR_NET_WRITE || ret == TS_ERR_NET_EOF) {
- Debug("ts_main", "[ts_ctrl_main] ERROR:handle_record_set\n");
- remove_client(client_entry, accepted_con);
- con_entry = ink_hash_table_iterator_next(accepted_con, &con_state);
- continue;
- }
-
break;
case FILE_READ:
ret = handle_file_read(client_entry->sock_info, req);
- ats_free(req);
- if (ret == TS_ERR_NET_WRITE || ret == TS_ERR_NET_EOF) {
- Debug("ts_main", "[ts_ctrl_main] ERROR:handle_file_read\n");
- remove_client(client_entry, accepted_con);
- con_entry = ink_hash_table_iterator_next(accepted_con, &con_state);
- continue;
- }
-
break;
case FILE_WRITE:
ret = handle_file_write(client_entry->sock_info, req);
- ats_free(req);
- if (ret == TS_ERR_NET_WRITE || ret == TS_ERR_NET_EOF) {
- Debug("ts_main", "[ts_ctrl_main] ERROR:handle_file_write\n");
- remove_client(client_entry, accepted_con);
- con_entry = ink_hash_table_iterator_next(accepted_con, &con_state);
- continue;
- }
-
break;
case PROXY_STATE_GET:
ret = handle_proxy_state_get(client_entry->sock_info);
- ats_free(req); // free the request allocated by preprocess_msg
- if (ret == TS_ERR_NET_WRITE || ret == TS_ERR_NET_EOF) {
- Debug("ts_main", "[ts_ctrl_main] ERROR:handle_proxy_state_get\n");
- remove_client(client_entry, accepted_con);
- con_entry = ink_hash_table_iterator_next(accepted_con, &con_state);
- continue;
- }
-
break;
case PROXY_STATE_SET:
ret = handle_proxy_state_set(client_entry->sock_info, req);
- ats_free(req); // free the request allocated by preprocess_msg
- if (ret == TS_ERR_NET_WRITE || ret == TS_ERR_NET_EOF) {
- Debug("ts_main", "[ts_ctrl_main] ERROR:handle_proxy_state_set\n");
- remove_client(client_entry, accepted_con);
- con_entry = ink_hash_table_iterator_next(accepted_con, &con_state);
- continue;
- }
-
break;
case RECONFIGURE:
ret = handle_reconfigure(client_entry->sock_info);
- ats_free(req); // free the request allocated by preprocess_msg
- if (ret == TS_ERR_NET_WRITE || ret == TS_ERR_NET_EOF) {
- Debug("ts_main", "[ts_ctrl_main] ERROR:handle_reconfigure\n");
- remove_client(client_entry, accepted_con);
- con_entry = ink_hash_table_iterator_next(accepted_con, &con_state);
- continue;
- }
-
break;
case RESTART:
ret = handle_restart(client_entry->sock_info, req, false);
- ats_free(req); // free the request allocated by preprocess_msg
- if (ret == TS_ERR_NET_WRITE || ret == TS_ERR_NET_EOF) {
- Debug("ts_main", "[ts_ctrl_main] ERROR:handle_restart\n");
- remove_client(client_entry, accepted_con);
- con_entry = ink_hash_table_iterator_next(accepted_con, &con_state);
- continue;
- }
break;
case BOUNCE:
ret = handle_restart(client_entry->sock_info, req, true);
- ats_free(req); // free the request allocated by preprocess_msg
- if (ret == TS_ERR_NET_WRITE || ret == TS_ERR_NET_EOF) {
- Debug("ts_main", "[ts_ctrl_main] ERROR:handle_restart bounce\n");
- remove_client(client_entry, accepted_con);
- con_entry = ink_hash_table_iterator_next(accepted_con, &con_state);
- continue;
- }
break;
case STORAGE_DEVICE_CMD_OFFLINE:
ret = handle_storage_device_cmd_offline(client_entry->sock_info, req);
- ats_free(req); // free the request allocated by preprocess_msg
- if (ret == TS_ERR_NET_WRITE || ret == TS_ERR_NET_EOF) {
- Debug("ts_main", "[ts_ctrl_main] ERROR:handle_storage_device_cmd_offline\n");
- remove_client(client_entry, accepted_con);
- con_entry = ink_hash_table_iterator_next(accepted_con, &con_state);
- continue;
- }
break;
case EVENT_RESOLVE:
ret = handle_event_resolve(client_entry->sock_info, req);
- ats_free(req); // free the request allocated by preprocess_msg
- if (ret == TS_ERR_NET_WRITE || ret == TS_ERR_NET_EOF) {
- Debug("ts_main", "[ts_ctrl_main] ERROR:handle_event_resolve\n");
- remove_client(client_entry, accepted_con);
- con_entry = ink_hash_table_iterator_next(accepted_con, &con_state);
- continue;
- }
break;
case EVENT_GET_MLT:
ret = handle_event_get_mlt(client_entry->sock_info);
- ats_free(req); // free the request allocated by preprocess_msg
- if (ret == TS_ERR_NET_WRITE || ret == TS_ERR_NET_EOF) {
- Debug("ts_main", "[ts_ctrl_main] ERROR:event_get_mlt\n");
- remove_client(client_entry, accepted_con);
- con_entry = ink_hash_table_iterator_next(accepted_con, &con_state);
- continue;
- }
break;
case EVENT_ACTIVE:
ret = handle_event_active(client_entry->sock_info, req);
- ats_free(req); // free the request allocated by preprocess_msg
- if (ret == TS_ERR_NET_WRITE || ret == TS_ERR_NET_EOF) {
- Debug("ts_main", "[ts_ctrl_main] ERROR:event_active\n");
- remove_client(client_entry, accepted_con);
- con_entry = ink_hash_table_iterator_next(accepted_con, &con_state);
- continue;
- }
break;
case SNAPSHOT_TAKE:
case SNAPSHOT_RESTORE:
case SNAPSHOT_REMOVE:
ret = handle_snapshot(client_entry->sock_info, req, op_t);
- ats_free(req);
- if (ret == TS_ERR_NET_WRITE || ret == TS_ERR_NET_EOF) {
- Debug("ts_main", "[ts_ctrl_main] ERROR:handle_snapshot\n");
- remove_client(client_entry, accepted_con);
- con_entry = ink_hash_table_iterator_next(accepted_con, &con_state);
- continue;
- }
break;
case SNAPSHOT_GET_MLT:
ret = handle_snapshot_get_mlt(client_entry->sock_info);
- ats_free(req);
- if (ret == TS_ERR_NET_WRITE || ret == TS_ERR_NET_EOF) {
- Debug("ts_main", "[ts_ctrl_main] ERROR:snapshot_get_mlt\n");
- remove_client(client_entry, accepted_con);
- con_entry = ink_hash_table_iterator_next(accepted_con, &con_state);
- continue;
- }
break;
case DIAGS:
- if (req) {
- handle_diags(client_entry->sock_info, req);
- ats_free(req);
- }
+ ret = handle_diags(client_entry->sock_info, req);
break;
case STATS_RESET_CLUSTER:
case STATS_RESET_NODE:
ret = handle_stats_reset(client_entry->sock_info, req, op_t);
- ats_free(req);
- if (ret == TS_ERR_NET_WRITE || ret == TS_ERR_NET_EOF) {
- Debug("ts_main", "[ts_ctrl_main] ERROR: stats_reset\n");
- remove_client(client_entry, accepted_con);
- con_entry = ink_hash_table_iterator_next(accepted_con, &con_state);
- continue;
- }
break;
case UNDEFINED_OP:
@@ -409,6 +294,16 @@ ts_ctrl_main(void *arg)
break;
} // end switch (op_t)
+
+ ats_free(req);
+
+ if (ret == TS_ERR_NET_WRITE || ret == TS_ERR_NET_EOF) {
+ Debug("ts_main", "[ts_ctrl_main] ERROR: sending response for message op %d\n", (int)op_t);
+ remove_client(client_entry, accepted_con);
+ con_entry = ink_hash_table_iterator_next(accepted_con, &con_state);
+ continue;
+ }
+
} // end if(client_entry->sock_info.fd && FD_ISSET(client_entry->sock_info.fd, &selectFDs))
con_entry = ink_hash_table_iterator_next(accepted_con, &con_state);
@@ -487,16 +382,16 @@ handle_record_get(struct SocketInfo sock_info, char *req)
// create and send reply back to client
switch (ele->rec_type) {
case TS_REC_INT:
- ret = send_record_get_reply(sock_info, ret, &(ele->int_val), sizeof(TSInt), ele->rec_type);
+ ret = send_record_get_reply(sock_info, ret, &(ele->int_val), sizeof(TSInt), ele->rec_type, ele->rec_name);
break;
case TS_REC_COUNTER:
- ret = send_record_get_reply(sock_info, ret, &(ele->counter_val), sizeof(TSCounter), ele->rec_type);
+ ret = send_record_get_reply(sock_info, ret, &(ele->counter_val), sizeof(TSCounter), ele->rec_type, ele->rec_name);
break;
case TS_REC_FLOAT:
- ret = send_record_get_reply(sock_info, ret, &(ele->float_val), sizeof(TSFloat), ele->rec_type);
+ ret = send_record_get_reply(sock_info, ret, &(ele->float_val), sizeof(TSFloat), ele->rec_type, ele->rec_name);
break;
case TS_REC_STRING:
- ret = send_record_get_reply(sock_info, ret, ele->string_val, strlen(ele->string_val), ele->rec_type);
+ ret = send_record_get_reply(sock_info, ret, ele->string_val, strlen(ele->string_val), ele->rec_type, ele->rec_name);
break;
default: // invalid record type
ret = send_reply(sock_info, TS_ERR_FAIL);
@@ -513,6 +408,70 @@ handle_record_get(struct SocketInfo sock_info, char *req)
return ret;
}
+struct record_match_state {
+ TSError err;
+ SocketInfo sock;
+ DFA regex;
+};
+
+static void
+send_record_match(RecT /* rec_type */, void *edata, int /* registered */, const char *name, int data_type, RecData *rec_val)
+{
+ record_match_state *match = (record_match_state *)edata ;
+
+ if (match->err != TS_ERR_OKAY) {
+ return;
+ }
+
+ if (match->regex.match(name) >= 0) {
+ switch (data_type) {
+ case RECD_INT:
+ match->err = send_record_get_reply(match->sock, TS_ERR_OKAY, &(rec_val->rec_int), sizeof(TSInt), TS_REC_INT, name);
+ break;
+ case RECD_COUNTER:
+ match->err = send_record_get_reply(match->sock, TS_ERR_OKAY, &(rec_val->rec_counter), sizeof(TSCounter), TS_REC_COUNTER, name);
+ break;
+ case RECD_STRING:
+ match->err = send_record_get_reply(match->sock, TS_ERR_OKAY, rec_val->rec_string, rec_val->rec_string ? strlen(rec_val->rec_string): 0, TS_REC_STRING, name);
+ break;
+ case RECD_FLOAT:
+ match->err = send_record_get_reply(match->sock, TS_ERR_OKAY, &(rec_val->rec_float), sizeof(TSFloat), TS_REC_FLOAT, name);
+ break;
+ default:
+ break; // skip it
+ }
+ }
+}
+
+TSError
+handle_record_match(struct SocketInfo sock_info, char *req)
+{
+ TSError ret;
+ record_match_state match;
+
+ // parse msg - don't really need since the request itself is the regex itself
+ if (!req) {
+ ret = send_reply(sock_info, TS_ERR_FAIL);
+ return ret;
+ }
+
+ if (match.regex.compile(req, RE_CASE_INSENSITIVE) != 0) {
+ ret = send_reply(sock_info, TS_ERR_FAIL);
+ return ret;
+ }
+
+ match.err = TS_ERR_OKAY;
+ match.sock = sock_info;
+
+ RecDumpRecords(RECT_NULL, send_record_match, &match);
+
+ // If successful, send a list terminator.
+ if (match.err == TS_ERR_OKAY) {
+ return send_record_get_reply(sock_info, TS_ERR_OKAY, NULL, 0, TS_REC_UNDEFINED, NULL);
+ }
+
+ return match.err;
+}
/**************************************************************************
* handle_record_set
@@ -957,7 +916,7 @@ handle_snapshot_get_mlt(struct SocketInfo sock_info)
* req - the diag message (already formatted with arguments)
* output: TS_ERR_xx
*************************************************************************/
-void
+TSError
handle_diags(struct SocketInfo /* sock_info ATS_UNUSED */, char *req)
{
TSError ret;
@@ -1008,12 +967,12 @@ handle_diags(struct SocketInfo /* sock_info ATS_UNUSED */, char *req)
if (diags_init) {
diags->print("TSMgmtAPI", DTA(level), "%s", diag_msg);
ats_free(diag_msg);
- return;
+ return TS_ERR_OKAY;
}
Lerror:
ats_free(diag_msg);
- return;
+ return TS_ERR_FAIL;
}
/**************************************************************************
http://git-wip-us.apache.org/repos/asf/trafficserver/blob/0389be39/mgmt/api/TSControlMain.h
----------------------------------------------------------------------
diff --git a/mgmt/api/TSControlMain.h b/mgmt/api/TSControlMain.h
index 397b8bb..b53603e 100644
--- a/mgmt/api/TSControlMain.h
+++ b/mgmt/api/TSControlMain.h
@@ -49,6 +49,7 @@ void delete_client(ClientT * client);
void *ts_ctrl_main(void *arg);
TSError handle_record_get(struct SocketInfo sock_info, char *req);
+TSError handle_record_match(struct SocketInfo sock_info, char *req);
TSError handle_record_set(struct SocketInfo sock_info, char *req);
TSError handle_file_read(struct SocketInfo sock_info, char *req);
@@ -67,7 +68,7 @@ TSError handle_event_active(struct SocketInfo sock_info, char *req);
TSError handle_snapshot(struct SocketInfo sock_info, char *req, OpType op);
TSError handle_snapshot_get_mlt(struct SocketInfo sock_info);
-void handle_diags(struct SocketInfo sock_info, char *req);
+TSError handle_diags(struct SocketInfo sock_info, char *req);
TSError handle_stats_reset(struct SocketInfo sock_info, char *req, OpType op);
http://git-wip-us.apache.org/repos/asf/trafficserver/blob/0389be39/mgmt/api/include/mgmtapi.h
----------------------------------------------------------------------
diff --git a/mgmt/api/include/mgmtapi.h b/mgmt/api/include/mgmtapi.h
index 7b88d92..786db7f 100644
--- a/mgmt/api/include/mgmtapi.h
+++ b/mgmt/api/include/mgmtapi.h
@@ -1174,6 +1174,12 @@ extern "C"
*/
tsapi TSError TSRecordGetMlt(TSStringList rec_names, TSList rec_vals);
+/* TSRecordGetMatchMlt: gets a set of records
+ * Input: rec_regex - regular expression to match against record names
+ * Output: TSError, TSList of TSRecordEle
+ */
+ tsapi TSError TSRecordGetMatchMlt(const char *rec_regex, TSList list);
+
/* TSRecordSet*: sets a record w/ a known type
* Input: rec_name - the name of the record (proxy.config.record_name)
* *_val - the value to set the record to