Error Handling
The server has several APIs and built-in mechanisms for generating error responses for client requests. This is done is a protocol-independent way. The error reporting procedures and data sre protocol-specific, but these are handled automatically by the server.
RPC Error Example
Assuming the “interfaces” container preexist in the datastore. To invoke the callback the following RPC can be sent. This example contains an error so a RESTCONF <errors> block will be sent to the client.
<rpc message-id="101" xmlns="urn:ietf:params:xml:ns:netconf:base:1.0">
<edit-config>
<target>
<candidate/>
</target>
<config>
<interfaces xmlns="http://yumaworks.com/ns/ietf-interfaces-example">
<interface>
<name>not-supported</name>
</interface>
</interfaces>
</config>
</edit-config>
</rpc>
The server may reply with the following:
<errors xmlns:ncx="http://netconfcentral.org/ns/yuma-ncx"
xmlns="urn:ietf:params:xml:ns:yang:ietf-restconf">
<error>
<error-type>rpc</error-type>
<error-tag>operation-not-supported</error-tag>
<error-app-tag>no-support</error-app-tag>
<error-message xml:lang="en">operation not supported</error-message>
<error-info>
<error-number>273</error-number>
</error-info>
</error>
</errors>
RPC Error Message
NETCONF has several standard error fields that are returned in an <rpc-error> response. These are defined in RFC 6241, section 4.3.
RESTCONF defines its own structure to return for errors, but it has the same child fields as NETCONF. Only the container structure is different. These are defined in RFC 8040.
error-type
Mandatory field set by the server indicating the protocol layer where the error occurred.
One of:
transport
rpc
protocol
application
The 'ncx_layer_t' enumeration defined in ncx/ncxtypes.h
is used for this field.
-
enum ncx_layer_t
Enumeration of NETCONF protocol layers.
Values:
-
enumerator NCX_LAYER_NONE
not set
-
enumerator NCX_LAYER_TRANSPORT
transport layer
-
enumerator NCX_LAYER_RPC
RPC operation layer.
-
enumerator NCX_LAYER_OPERATION
protocol operation layer
-
enumerator NCX_LAYER_CONTENT
application layer
-
enumerator NCX_LAYER_NONE
error-tag
Mandatory enumeration for the type of error that occurred. This field is set by the server depending on the 'status_t' of the error. The values are defined in RFC 6241, Appendix A.
One of:
in-use
invalid-value
too-big
missing-attribute
bad-attribute
unknown-attribute
missing-element
bad-element
unknown-element
unknown-namespace
access-denied
lock-denied
resource-denied
rollback-failed
data-exists
data-missing
operation-not-supported
operation-failed
malformed-message
The 'rpc_err_t' enumeration defined in ncx/rpc_err.h
is used for this field.
-
enum rpc_err_t
enumerations for NETCONF standard errors
Values:
-
enumerator RPC_ERR_NONE
not set
-
enumerator RPC_ERR_IN_USE
in-use
-
enumerator RPC_ERR_INVALID_VALUE
invalid-value
-
enumerator RPC_ERR_TOO_BIG
too-big
-
enumerator RPC_ERR_MISSING_ATTRIBUTE
missing-attribute
-
enumerator RPC_ERR_BAD_ATTRIBUTE
bad-attribute
-
enumerator RPC_ERR_UNKNOWN_ATTRIBUTE
unknown-attribute
-
enumerator RPC_ERR_MISSING_ELEMENT
missing-element
-
enumerator RPC_ERR_BAD_ELEMENT
bad-element
-
enumerator RPC_ERR_UNKNOWN_ELEMENT
unknown-element
-
enumerator RPC_ERR_UNKNOWN_NAMESPACE
unknown-namespace
-
enumerator RPC_ERR_ACCESS_DENIED
access-denied
-
enumerator RPC_ERR_LOCK_DENIED
lock-denied
-
enumerator RPC_ERR_RESOURCE_DENIED
resource-denied
-
enumerator RPC_ERR_ROLLBACK_FAILED
rollback-failed
-
enumerator RPC_ERR_DATA_EXISTS
data-exists
-
enumerator RPC_ERR_DATA_MISSING
data-missing
-
enumerator RPC_ERR_OPERATION_NOT_SUPPORTED
operation-not-supported
-
enumerator RPC_ERR_OPERATION_FAILED
operation-failed
-
enumerator RPC_ERR_PARTIAL_OPERATION
partial-operation, deprecated; not used
-
enumerator RPC_ERR_MALFORMED_MESSAGE
malformed-message
-
enumerator RPC_ERR_NONE
error-severity
Mandatory field set by the server.
The value error
is (almost) always used because no standard
error-tag values are defined with a severity of warning
.
One of:
error
warning
The 'rpc_err_sev_t' enumeration defined in ncx/rpc_err.h
is used for this field.
-
enum rpc_err_sev_t
enumerations for NETCONF standard error severities
The protocol does not actually use RPC warnings and these are not supported or used in the server
Values:
-
enumerator RPC_ERR_SEV_NONE
not set
-
enumerator RPC_ERR_SEV_WARNING
warning
-
enumerator RPC_ERR_SEV_ERROR
error (only used value)
-
enumerator RPC_ERR_SEV_NONE
Note
The warning
enumeration can be used even though it is not standard.
The --with-warnings CLI parameter must be used to enable this feature in the server.
If set then the agt_record_warning API function can be used to
record a warning instead of an error.
error-app-tag
Optional field identifying the application-specific error. There are some standard values defined by YANG that must be used in certain error conditions.
The server will use these values even if error-app-tag values are defined for the specific errors instead:
must-violation
instance-required
missing-choice
missing-instance
Reserved NETCONF error-app-tag Values
Several values are defined in NETCONF standards. These cannot be redefined in the server.
#define RPC_ERR_APPTAG_UNIQUE_FAILED (const xmlChar *)"data-not-unique"
#define RPC_ERR_APPTAG_MAX_ELEMS (const xmlChar *)"too-many-elements"
#define RPC_ERR_APPTAG_MIN_ELEMS (const xmlChar *)"too-few-elements"
#define RPC_ERR_APPTAG_MUST (const xmlChar *)"must-violation"
#define RPC_ERR_APPTAG_INSTANCE_REQ (const xmlChar *)"instance-required"
#define RPC_ERR_APPTAG_CHOICE (const xmlChar *)"missing-choice"
#define RPC_ERR_APPTAG_INSERT (const xmlChar *)"missing-instance"
#define RPC_ERR_APPTAG_RANGE (const xmlChar *)"not-in-range"
#define RPC_ERR_APPTAG_VALUE_SET (const xmlChar *)"not-in-value-set"
#define RPC_ERR_APPTAG_PATTERN (const xmlChar *)"pattern-test-failed"
#define RPC_ERR_APPTAG_DATA_REST (const xmlChar *)"data-restriction-violation"
#define RPC_ERR_APPTAG_DATA_NOT_UNIQUE (const xmlChar *)"data-not-unique"
#define RPC_ERR_APPTAG_NO_MATCHES (const xmlChar *)"no-matches"
#define RPC_ERR_APPTAG_NOT_NODESET (const xmlChar *)"not-a-node-set"
#define RPC_ERR_APPTAG_LOCKED (const xmlChar *)"locked"
#define RPC_ERR_APPTAG_COMMIT (const xmlChar *)"outstanding-confirmed-commit"
Reserved YumaPro error-app-tag Values
Several values are defined by YumaPro conventions and are built into the server implementation. These cannot be redefined in the server.
#define RPC_ERR_APPTAG_GEN_WARNING (const xmlChar *)"general-warning"
#define RPC_ERR_APPTAG_GEN_ERROR (const xmlChar *)"general-error"
#define RPC_ERR_APPTAG_INT_ERROR (const xmlChar *)"internal-error"
#define RPC_ERR_APPTAG_IO_ERROR (const xmlChar *)"io-error"
#define RPC_ERR_APPTAG_MALLOC_ERROR (const xmlChar *)"malloc-error"
#define RPC_ERR_APPTAG_LIMIT_REACHED (const xmlChar *)"limit-reached"
#define RPC_ERR_APPTAG_LIBXML2_ERROR (const xmlChar *)"libxml2-error"
#define RPC_ERR_APPTAG_SQL_ERROR (const xmlChar *)"sql-error"
#define RPC_ERR_APPTAG_SSH_ERROR (const xmlChar *)"ssh-error"
#define RPC_ERR_APPTAG_BEEP_ERROR (const xmlChar *)"beep-error"
#define RPC_ERR_APPTAG_HTML_ERROR (const xmlChar *)"html-error"
#define RPC_ERR_APPTAG_DATA_INCOMPLETE (const xmlChar *)"data-incomplete"
#define RPC_ERR_APPTAG_DATA_INVALID (const xmlChar *)"data-invalid"
#define RPC_ERR_APPTAG_DUPLICATE_ERROR (const xmlChar *)"duplicate-error"
#define RPC_ERR_APPTAG_RESOURCE_IN_USE (const xmlChar *)"resource-in-use"
#define RPC_ERR_APPTAG_NO_ACCESS (const xmlChar *)"no-access"
#define RPC_ERR_APPTAG_RECOVER_FAILED (const xmlChar *)"recover-failed"
#define RPC_ERR_APPTAG_NO_SUPPORT (const xmlChar *)"no-support"
Reserved YANG Push error-app-tag Values
Several values are defined by Subscribed Notifications (RFC 8639) and YANG Push (RFC 8641). These are built into the server implementation and used if the "yang-push" bundle is loaded into the server. These cannot be redefined in the server.
/*** ietf-subscribed-notifications ***/
#define RPC_ERR_APPTAG_NOTIF_DSCP_UNAVAILABLE \
(const xmlChar *)"ietf-subscribed-notifications:dscp-unavailable"
#define RPC_ERR_APPTAG_NOTIF_ENCODING_UNSUPPORTED \
(const xmlChar *)"ietf-subscribed-notifications:encoding-unsupported"
#define RPC_ERR_APPTAG_NOTIF_FILTER_UNAVAILABLE \
(const xmlChar *)"ietf-subscribed-notifications:filter-unavailable"
#define RPC_ERR_APPTAG_NOTIF_FILTER_UNSUPPORTED \
(const xmlChar *)"ietf-subscribed-notifications:filter-unsupported"
#define RPC_ERR_APPTAG_NOTIF_INSUFFICIENT_RESOURCES \
(const xmlChar *)"ietf-subscribed-notifications:insufficient-resources"
#define RPC_ERR_APPTAG_NOTIF_NO_SUCH_SUBSCRIPTION \
(const xmlChar *)"ietf-subscribed-notifications:no-such-subscription"
#define RPC_ERR_APPTAG_NOTIF_REPLAY_UNSUPPORTED \
(const xmlChar *)"ietf-subscribed-notifications:replay-unsupported"
#define RPC_ERR_APPTAG_NOTIF_STREAM_UNAVAILABLE \
(const xmlChar *)"ietf-subscribed-notifications:stream-unavailable"
/*** ietf-yang-push errors ***/
#define RPC_ERR_APPTAG_PUSH_CANT_EXCLUDE \
(const xmlChar *)"ietf-yang-push:cant-exclude"
#define RPC_ERR_APPTAG_PUSH_DATASTORE_NOT_SUBSCRIBABLE \
(const xmlChar *)"ietf-yang-push:datastore-not-subscribable"
#define RPC_ERR_APPTAG_PUSH_NO_SUCH_RESYNC \
(const xmlChar *)"ietf-yang-push:no-such-subscription-resync"
#define RPC_ERR_APPTAG_PUSH_ON_CHANGE_UNSUPPORTED \
(const xmlChar *)"ietf-yang-push:on-change-unsupported"
#define RPC_ERR_APPTAG_PUSH_ON_CHANGE_SYNC_UNSUPPORTED \
(const xmlChar *)"ietf-yang-push:on-change-sync-unsupported"
#define RPC_ERR_APPTAG_PUSH_PERIOD_UNSUPPORTED \
(const xmlChar *)"ietf-yang-push:period-unsupported"
#define RPC_ERR_APPTAG_PUSH_UPDATE_TOO_BIG \
(const xmlChar *)"ietf-yang-push:update-too-big"
#define RPC_ERR_APPTAG_PUSH_SYNC_TOO_BIG \
(const xmlChar *)"ietf-yang-push:sync-too-big"
#define RPC_ERR_APPTAG_PUSH_UNCHANGING_SELECTION \
(const xmlChar *)"ietf-yang-push:unchanging-selection"
error-path
Optional field containing an XPath absolute path expression identifying the node that caused the error. Will be present if the user input can be associated with the error.
This field is generated by the server depending on the parameters passed to the "record error" API functions.
error-message
Optional field containing a short error message. The server always generates an error-message field. A default error message for the Return Status will be returned if no custom message has been configured or provided by a SIL or SIL-SA callback function.
error-info
This optional field is a container that has child data nodes representing additional error information. Some NETCONF errors require that certain error-info child nodes be present, depending on the error-tag value
The following 'error-tag' values have specific error-info elements that are required:
bad-attribute
bad-element
bad-namespace
session-id
The server will generate the required data automatically for these errors.
Error Handling APIs
The server has several APIs for setting error information that will be returned to a client in an <rpc-error> message. Each API allows different amounts of context-specific information included in the error response.
Return Status |
The 'status_t' enumeration returned by the SIL or SIL-SA code will be checked. If not error information has been recorded, then the server will construct an <rpc-error> based on the return status |
SET_ERROR |
The 'SET_ERROR' macro is for internal programming errors only. DO NOT USE! |
agt_record_error |
The 'agt_record_error' API allows the basic error fields to be set |
agt_record_error_errinfo |
The 'agt_record_error_errinfo' API allows all fields to be set, including over-riding the default error-message and error-app-tag fields. |
agt_record_warning |
The 'agt_record_warning' API allows a warning to be sent instead of an error |
Return Status (status_t)
The 'status_t' is used to convey internal or protocol error conditions.
The internal status codes are defined in
ncx/status_enum.h
The value 0 (NO_ERR) is used to indicate success.
Values 1 to 999 are error codes.
Values 1000 to 1999 are warning codes
Values 2000 to 2999 are system return codes
Error strings are defined in
netconf/src/ncx/status.c
in the 'get_error_string' function for each enumeration defined in status_enum.hEach status_t enumeration is mapped to an 'error-tag' value in the file
netconf/src/agt/agt_rpcerr.c
in the function 'get_rpcerr'. This mapping also includes the default 'error-app-tag' valueThe default 'error-message' and 'error-app-tag' values can be overridden using the YANG statements with the same name. These fields can also be specified internally (without adding these YANG statements) using the 'agt_record_error_errinfo' function instead of the 'agt_record_error' function.
-
const char *get_error_string(status_t res)
Get the error message for a specific internal error.
- Parameters:
res -- internal status_t error code
- Returns:
const pointer to error message
SET_ERROR
The 'SET_ERROR' macro is for programming errors, not client errors!
The macro is defined in ncx/status.h
and it is for
flagging internal errors only. This macro must not be used for normal
errors.
Warning
Do not use the SET_ERROR macro to return normal errors. This macro will cause “assert(0)” to be invoked, halting program execution.
This macro is used in some programming constructs to detect certain programming errors.
For example, switch statements for "enum" switches are required to have a "default" clause in YumaPro code. All known enum values must be handled. If a new enum is defined then the SET_ERROR will be hit if the switch has not been updated properly to handle the new value.
switch (cbtyp) {
case AGT_CB_VALIDATE:
/* description-stmt validation here */
break;
case AGT_CB_APPLY:
/* database manipulation done here */
break;
case AGT_CB_COMMIT:
/* device instrumentation done here */
switch (editop) {
case OP_EDITOP_LOAD:
break;
case OP_EDITOP_MERGE:
break;
case OP_EDITOP_REPLACE:
break;
case OP_EDITOP_CREATE:
break;
case OP_EDITOP_DELETE:
break;
default:
res = SET_ERROR(ERR_INTERNAL_VAL);
}
break;
case AGT_CB_ROLLBACK:
/* undo device instrumentation here */
break;
default:
res = SET_ERROR(ERR_INTERNAL_VAL);
}
agt_record_error
NETCONF and RESTCONF use a common data structure to report errors, defined in RFC 6241 Section 4.3.
Server errors are recorded with a set of APIs that allow complete control of the <rpc-error> contents.
The 'agt_record_error' function is one of the main error handling functions used in SIL or SIL-SA code.
If a specific error is not recorded by SIL code when an EDIT1, EDIT2, or EDIT3 callback is invoked. then the server will record a generic error, based on the 'status_t' returned by the SIL code.
-
void agt_record_error(ses_cb_t *scb, xml_msg_hdr_t *msghdr, ncx_layer_t layer, status_t res, const xml_node_t *xmlnode, ncx_node_t parmtyp, const void *error_info, ncx_node_t nodetyp, void *error_path)
Generate an rpc_err_rec_t and save it in the msg.
This is the main SIL or SIL-SA API to return an <rpc-error> to the NETCONF or RESTCONF client.
- Parameters:
scb -- [inout]
session control block
NULL and no stats will be recorded
scb->stats may be updated if scb non-NULLmsghdr -- [inout]
XML msg header with error Q
NULL, no errors will be recorded!
msghdr->errQ has error message added if not NULL and no malloc errorslayer -- netconf layer error occured. Used for <error-type> field.
res -- internal error code. Will get mapped to <error-tag> and <error-app-tag>
xmlnode --
XML node causing error. Will be used for <bad-element> and maybe error <error-path>
NULL if not available
parmtyp -- type of node in 'error_info'
error_info --
error data, specific to 'res'. Used to generate <error-info> sub-elements.
NULL if not available (then nodetyp ignored)
nodetyp -- type of node in 'error_path'
error_path --
internal data node with the error. Used to generate the <error-path> field
NULL if not available or not used
Example:
/* if error: set the res, errorstr, and errorval parms */
if (res != NO_ERR) {
agt_record_error(scb, // session control block
RPC_MHDR(msg), // xml_msg_hdr for the request state
NCX_LAYER_CONTENT, // <error-type> enum
res, // internal status code
NULL, // XML node (parser mode)
NCX_NT_STRING, // node type for error_info parm
errorstr, // node value for <error-info> struct
NCX_NT_VAL, // node type for the error_path parm
errorval); // node for the <error-path> field
}
This API function generates an rpc_err_rec_t and save it in the message.
agt_record_error_errinfo
The agt_record_error_errinfo function can be used to report extended error information.
In order to add any extended error information to the response message, the agt_record_error_errinfo function should be used. This function is the same as the previous one if the errinfo parameter is set to NULL.
-
void agt_record_error_errinfo(ses_cb_t *scb, xml_msg_hdr_t *msghdr, ncx_layer_t layer, status_t res, const xml_node_t *xmlnode, ncx_node_t parmtyp, const void *error_info, ncx_node_t nodetyp, void *error_path, const ncx_errinfo_t *errinfo)
Generate an rpc_err_rec_t and save it in the msg Use provided error fields.
This is the main SIL or SIL-SA API to return an <rpc-error> to the NETCONF or RESTCONF client.
- Parameters:
scb -- [inout]
session control block
NULL and no stats will be recorded
scb->stats may be updated if scb non-NULLmsghdr -- [inout]
XML msg header with error Q
NULL, no errors will be recorded!
msghdr->errQ has error message added if not NULL and no malloc errorslayer -- netconf layer error occured. Used for <error-type> field.
res -- internal error code. Will get mapped to <error-tag> and <error-app-tag>
xmlnode --
XML node causing error. Will be used for <bad-element> and maybe error <error-path>
NULL if not available
parmtyp -- type of node in 'error_info'
error_info --
error data, specific to 'res'. Used to generate <error-info> sub-elements.
NULL if not available (then nodetyp ignored)
nodetyp -- type of node in 'error_path'
error_path --
internal data node with the error. Used to generate the <error-path> field
NULL if not available or not used
errinfo -- error info record to use (may be NULL)
agt_record_warning
The agt_record_warning function can be used to report a warning instead of an error.
An <rpc-error> element will still be used, however, the <error-severity> will
be set to warning
instead of error
-
void agt_record_warning(ses_cb_t *scb, xml_msg_hdr_t *msghdr, ncx_layer_t layer, status_t res, const xml_node_t *xmlnode, ncx_node_t parmtyp, const void *error_parm, ncx_node_t nodetyp, void *error_path, const ncx_errinfo_t *errinfo)
Generate an rpc_err_rec_t and save it in the msg.
Not actually supported in NETCONF protocol because no standard error-tag values are defined for severity=warning
Use the provided error info record for <rpc-error> fields Set the error-severity field to warning instead of error but only if agt_with_warnings is TRUE
- Parameters:
scb -- [inout]
session control block
NULL and no stats will be recorded
scb->stats may be updated if scb non-NULLmsghdr -- [inout]
XML msg header with error Q
NULL, no errors will be recorded! msghdr->errQ has error message added if not NULL and no malloc errors
layer -- netconf layer error occured. Used for <error-type> field.
res -- internal error code. Will get mapped to <error-tag> and <error-app-tag>
xmlnode --
XML node causing error. Will be used for <bad-element> and maybe error <error-path>
NULL if not available
parmtyp -- type of node in 'error_info'
error_parm --
error data, specific to 'res'. Used to generate <error-info> sub-elements.
NULL if not available (then nodetyp ignored)
nodetyp -- type of node in 'error_path'
error_path --
internal data node with the error. Used to generate the <error-path> field
NULL if not available or not used
errinfo -- error info record to use (may be NULL)
SIL Creation of Custom Error Messages And AppInfo
The server maintains data structures for error information including the ncx_errinfo_t struct.
-
struct ncx_errinfo_t
YANG error info statement struct used to override default error handling in the server.
Normally this structure is static and derived from YANG statements.
It can also be provided at runtime by a SIL function using the agt_record_error_errinfo function.
This feature must be used with care because the strings within the structure and the structure itself must persist until the server has sent the error response message.
Only the error_app_tag and error_message fields will be checked. Do not set any other fields in this structure.
-
ncx_errinfo_t *ncx_new_errinfo(void)
Malloc and init a new ncx_errinfo_t.
- Returns:
pointer to malloced ncx_errinfo_t, or NULL if memory error
-
void ncx_free_errinfo(ncx_errinfo_t *err)
Scrub the memory in a ncx_errinfo_t by freeing all the sub-fields, then free the errinfo struct.
- Parameters:
err -- ncx_errinfo_t data structure to free
These strings are malloced (not const!) so the struct has to be setup by the SIL code.
The structure can be cleaned up using Transaction Complete callback after the transaction is complete.
The following example API shows how the ncx_errinfo_t struct can be created.
/* return an ncx_errinfo that must be freed with ncx_free_appinfo */
static ncx_errinfo_t *
make_errinfo (const xmlChar *apptag,
const xmlChar *errmsg)
{
ncx_errinfo_t *errinfo = ncx_new_errinfo();
if (errinfo == NULL) {
return NULL;
}
if (apptag != NULL) {
errinfo->error_app_tag = xml_strdup(apptag);
if (errinfo->error_app_tag == NULL) {
ncx_free_errinfo(errinfo);
return NULL;
}
}
if (errmsg != NULL) {
errinfo->error_message = xml_strdup(errmsg);
if (errinfo->error_message == NULL) {
ncx_free_errinfo(errinfo);
return NULL;
}
}
return errinfo;
}
SIL-SA Creation of Custom Error Messages And AppInfo
The following API provides a way to set a Custom Error message. In order to set a custom Error Message to be sent to the server the following API can be used. This API is only available to EDIT callbacks.
The following YANG module is used in this example:
module error-example {
namespace "http://netconfcentral.org/ns/error-example";
prefix "err";
revision 2021-11-19 {
description
"Example module";
}
container test-silsa-errors { // EDIT2 CB
presence "Presence";
leaf test-error {
type string;
}
}
}
Assume the SIL-SA code reports an error in case the 'test-error' leaf
creation and when the value of a new leaf is force-error
.
In this case there is an API 'sil_sa_set_error_msg' to set up a custom error to be returned to the server.
-
void sil_sa_set_error_msg(rpc_msg_t *msg, const xmlChar *strval)
Set Error Message string in case of error.
- Parameters:
msg -- rpc msg to use to find keys
strval -- string value to use for error message
status_t
u_err_test_silsa_errors_edit (
ses_cb_t *scb,
rpc_msg_t *msg,
agt_cbtyp_t cbtyp,
op_editop_t editop,
val_value_t *newval,
val_value_t *curval)
{
val_value_t *child_val = NULL;
if (newval) {
child_val =
val_find_child(newval,
(const xmlChar *)"error-example",
(const xmlChar *)"test-error");
}
/* Get the rpc message id (txid_str) from the rpc_sil_sa_cb */
const xmlChar *msg_id = sil_sa_get_rpc_msg_id(msg);
/* Get the user_id value from the message header */
const xmlChar *user = sil_sa_get_username();
/* Get the client address (client_addr value from the message header) */
const xmlChar *client_addr = sil_sa_get_client_addr();
if (LOGDEBUG3) {
log_debug3("\nEnter u_err_test_silsa_errors_edit");
log_debug3_append("\nmsg_id:%s", msg_id);
log_debug3_append("\nuser:%s", user);
log_debug3_append("\nclient_addr:%s", client_addr);
}
switch (cbtyp) {
case AGT_CB_VALIDATE:
/* description-stmt validation here */
break;
case AGT_CB_APPLY:
/* database manipulation done here */
break;
case AGT_CB_COMMIT:
/* device instrumentation done here */
switch (editop) {
case OP_EDITOP_LOAD:
break;
case OP_EDITOP_MERGE:
break;
case OP_EDITOP_REPLACE:
break;
case OP_EDITOP_CREATE:
if (child_val &&
!xml_strcmp(VAL_STR(child_val), (const xmlChar *)"force-error")) {
/* TRIGGER ERROR */
res = ERR_NCX_OPERATION_NOT_SUPPORTED;
sil_sa_set_error_msg(msg,
(const xmlChar *)"SOME CUSTOM ERROR MSG");
}
break;
case OP_EDITOP_DELETE:
break;
default:
/* USE SET_ERROR FOR PROGRAMMING BUGS ONLY */
res = SET_ERROR(ERR_INTERNAL_VAL);
}
break;
case AGT_CB_ROLLBACK:
/* undo device instrumentation here */
break;
default:
/* USE SET_ERROR FOR PROGRAMMING BUGS ONLY */
res = SET_ERROR(ERR_INTERNAL_VAL);
}
return res;
} /* u_err_test_silsa_errors_edit */
Adding <error-info> Data to an Error Response
The NETCONF <rpc-error> and RESTCONF <errors> data structures allow error data to be reported to the client. This data can be located in a container called “error-info”. Typically, the server adds an “error-number” leaf to this container, but there are several NETCONF errors that require specific error data to be returned.
Step 1) Define the error-info Data
The new API functions require the following H files, which need to be included into the SIL C file:
#include “agt_util.h”
#include “rpc.h”
The data returned to an <error-info> record should be defined in a real YANG module.
In the example below, an abstract leaf called 'testdata' is defined:
leaf testdata {
ncx:abstract;
type int32;
description
"Example of template for user <error-info> data";
}
Step 2) Create a Data Node and Add it to the Error Response.
The 'rpc_msg_add_error_data' function can be used to add custom <error-info> child nodes to an error response.
Only SIL Callbacks Can Use This Function
-
void rpc_msg_add_error_data(rpc_msg_t *msg, val_value_t *val)
Add error data to the response message.
Used by the server only
Add a val_value_t node that will be used in the error response sent to the client
- Parameters:
msg -- rpc_msg_t to add data into
val -- malloced error data node to add to error record error-info !!! This value node will be consumed and freed later !!!
The data created must be malloced so it can be freed later with the 'val_free_value' function.
The example from sil_error/src/sil-error.c
shows an instance of
testdata being created:
/********************************************************************
* FUNCTION add_user_error_data
*
* Add an example error-info data node to the error that is returned
* to the client
*
* INPUTS:
* msg == RPC message to add user error data
* RETURNS:
* status
********************************************************************/
static status_t
add_user_error_data (rpc_msg_t *msg)
{
/* get the abstract leaf template */
obj_template_t *testdata_obj =
obj_find_template_top(sil_error_mod,
sil_error_mod->name,
(const xmlChar *)"testdata");
if (testdata_obj == NULL) {
return ERR_NCX_DEF_NOT_FOUND;
}
/* a real add_user_data callback would probably get a system
* value instead of a constant; use constant here
*/
const xmlChar *valuebuff = (const xmlChar *)"42";
status_t res = NO_ERR;
val_value_t *testdata_val =
val_make_simval_obj(testdata_obj, valuebuff, &res);
if (testdata_val) {
rpc_msg_add_error_data(msg, testdata_val);
}
return res;
} /* add_user_error_data */
This step is done BEFORE the agt_record_error (or other variant) is called by the SIL code:
if (res != NO_ERR) {
/* add user data to the message before calling agt_record_error */
(void)add_user_error_data(msg);
agt_record_error(
scb,
&msg->mhdr,
NCX_LAYER_CONTENT,
res,
NULL,
(errorval) ? NCX_NT_VAL : NCX_NT_NONE,
errorval,
(errorval) ? NCX_NT_VAL : NCX_NT_NONE,
errorval);
}
Example Error Responses
The “sil-trigger” object is used to show how error-info data is added to the error response.
The error is triggered by setting /sil-phase to apply
and
/sil-trigger to any value. This will force an error to
generated upon the appropriate edit.
NETCONF Error Example
> merge /sil-trigger value=2
This might cause the following <rpc-error> response in NETCONF:
<?xml version="1.0" encoding="UTF-8"?>
<rpc-reply message-id="4" trace-id="4"
xmlns:silerr="http://www.netconfcentral.org/ns/sil-error"
xmlns:ncx="http://netconfcentral.org/ns/yuma-ncx"
xmlns="urn:ietf:params:xml:ns:netconf:base:1.0">
<rpc-error>
<error-type>application</error-type>
<error-tag>operation-failed</error-tag>
<error-severity>error</error-severity>
<error-app-tag>general-error</error-app-tag>
<error-path>/silerr:sil-trigger</error-path>
<error-message xml:lang="en">operation failed</error-message>
<error-info>
<error-number>274</error-number>
<testdata xmlns="http://www.netconfcentral.org/ns/sil-error">42</testdata>
</error-info>
</rpc-error>
</rpc-reply>
RESTCONF Error Example
The following example shows how RESTCONF will return the user error data:
If any errors occur while attempting to invoke the operation, then an "errors" data structure is returned with the appropriate error status.
XML Example
The client might send the following POST request message to invoke a "reboot" operation:
POST /restconf/operations/example-ops:reboot HTTP/1.1
Accept: application/yang-data+xml
Content-Type: application/yang-data+xml
<input xmlns="https://example.com/ns/example-ops">
<delay>-33</delay>
<message>Going down for system maintenance</message>
<language>en-US</language>
</input>
The server might respond with an "invalid-value" error in default XML format:
HTTP/1.1 400 Bad Request
Date: Mon, 25 Apr 2012 11:10:30 GMT
Server: example-server
Content-Type: application/yang-data+xml
<errors xmlns="urn:ietf:params:xml:ns:yang:ietf-restconf">
<error>
<error-type>protocol</error-type>
<error-tag>invalid-value</error-tag>
<error-path xmlns:err="https://example.com/ns/example-ops">err:input/err:delay</error-path>
<error-message>Invalid input parameter</error-message>
</error>
</errors>
JSON Example
If the client specifies application/yang-data+json
in the Accept header entry,
the server will respond in JSON format.
A lock-denied error might be sent as follows:
HTTP/1.1 409 Conflict
Date: Mon, 23 Apr 2012 17:11:00 GMT
Server: example-server
Content-Type: application/yang-data+json
{
"ietf-restconf:errors": {
"error": [
{
"error-type": "protocol",
"error-tag": "lock-denied",
"error-message": "Lock failed, lock already held"
}
]
}
}