diff options
Diffstat (limited to 'src/plugins/openconfig')
-rw-r--r-- | src/plugins/openconfig/openconfig_interfaces.c | 759 | ||||
-rw-r--r-- | src/plugins/openconfig/openconfig_interfaces.h | 26 | ||||
-rw-r--r-- | src/plugins/openconfig/openconfig_local_routing.c | 888 | ||||
-rw-r--r-- | src/plugins/openconfig/openconfig_local_routing.h | 25 |
4 files changed, 595 insertions, 1103 deletions
diff --git a/src/plugins/openconfig/openconfig_interfaces.c b/src/plugins/openconfig/openconfig_interfaces.c index c72ad7f..7242c2b 100644 --- a/src/plugins/openconfig/openconfig_interfaces.c +++ b/src/plugins/openconfig/openconfig_interfaces.c @@ -17,119 +17,72 @@ #include <assert.h> #include <string.h> -#include "openconfig_interfaces.h" -#include "../sys_util.h" - -#include "sc_vpp_comm.h" -#include "sc_vpp_interface.h" -#include "sc_vpp_ip.h" +#include <scvpp/comm.h> +#include <scvpp/interface.h> +#include <scvpp/ip.h> -#define XPATH_SIZE 2000 +#include "../sc_model.h" +#include "../sys_util.h" // XPATH: /openconfig-interfaces:interfaces/interface[name='%s']/config/ -int openconfig_interfaces_interfaces_interface_config_cb( +static int openconfig_interfaces_interfaces_interface_config_cb( sr_session_ctx_t *ds, const char *xpath, sr_notif_event_t event, - __attribute__((unused)) void *private_ctx) + void *private_ctx) { + UNUSED(private_ctx); sr_change_iter_t *it = NULL; sr_change_oper_t oper; - sr_val_t *old_val = NULL; - sr_val_t *new_val = NULL; + sr_xpath_ctx_t state = {0}; + sr_val_t *old = NULL; + sr_val_t *new = NULL; char *tmp = NULL; char interface_name[XPATH_SIZE] = {0}; int rc = 0; - SRP_LOG_INF_MSG("In openconfig_interfaces_interfaces_interface_config_cb"); + SRP_LOG_INF("In %s", __FUNCTION__); + SRP_LOG_INF("XPATH %s", xpath); ARG_CHECK2(SR_ERR_INVAL_ARG, ds, xpath); - // if we receive event SR_EV_APPLY - config has changed - - log_recv_event(event, "subtree_change_cb received"); - SRP_LOG_DBG("[SRP_LOG_DBG] xpath: %s", xpath); - - // apply configuration - // - // - // in this type i guess we can call sr_get_item() - // because we are subscribed to leaf we shouldn't - // get more than one change in one callback - // each chage represent change in a hierarchy of - // xml document - // - if (event != SR_EV_APPLY) { + if (event == SR_EV_APPLY) return SR_ERR_OK; - } - - // first we get event VERIFY - // then we get event APPLY - // - we can return error from VERIFY event - // - we can't return error from APPLY event if (sr_get_changes_iter(ds, (char *)xpath, &it) != SR_ERR_OK) { - // in example he calls even on fale sr_free_change_iter(it); return SR_ERR_OK; } - while (sr_get_change_next(ds, it, &oper, - &old_val, &new_val) == SR_ERR_OK) { + foreach_change (ds, it, oper, old, new) { - log_recv_oper(oper, "subtree_change_cb received"); + SRP_LOG_DBG("xpath: %s", new->xpath); - SRP_LOG_DBG("xpath: %s", new_val->xpath); - - sr_xpath_ctx_t state = {0}; - - tmp = xpath_find_first_key(new_val->xpath, "name", &state); - if (NULL == tmp) { - SRP_LOG_DBG_MSG("interface_name NOT found."); - continue; + tmp = sr_xpath_key_value(new->xpath, "interface", "name", &state); + if (!tmp) { + sr_set_error(ds, "XPATH interface name NOT found", new->xpath); + return SR_ERR_INVAL_ARG; } - strncpy(interface_name, tmp, XPATH_SIZE); sr_xpath_recover(&state); switch (oper) { case SR_OP_CREATED: - if (sr_xpath_node_name_eq(new_val->xpath, "name")) { - //TODO: LEAF: name, type: string - } else if(sr_xpath_node_name_eq(new_val->xpath, "type")) { - //TODO: LEAF: type, type: identityref - } else if(sr_xpath_node_name_eq(new_val->xpath, "mtu")) { - //TODO: LEAF: mtu, type: uint16 - } else if(sr_xpath_node_name_eq(new_val->xpath, - "loopback-mode")) { - //TODO: LEAF: loopback-mode, type: boolean - } else if(sr_xpath_node_name_eq(new_val->xpath, - "description")) { - //TODO: LEAF: description, type: string - } else if(sr_xpath_node_name_eq(new_val->xpath, "enabled")) { - rc = interface_enable(interface_name, - new_val->data.bool_val); - } else if(sr_xpath_node_name_eq(new_val->xpath, - "oc-vlan:tpid")) { - //TODO: LEAF: oc-vlan:tpid, type: identityref - } - break; - case SR_OP_MODIFIED: - if (sr_xpath_node_name_eq(new_val->xpath, "name")) { + if (sr_xpath_node_name_eq(new->xpath, "name")) { //TODO: LEAF: name, type: string - } else if(sr_xpath_node_name_eq(new_val->xpath, "type")) { + } else if(sr_xpath_node_name_eq(new->xpath, "type")) { //TODO: LEAF: type, type: identityref - } else if(sr_xpath_node_name_eq(new_val->xpath, "mtu")) { + } else if(sr_xpath_node_name_eq(new->xpath, "mtu")) { //TODO: LEAF: mtu, type: uint16 - } else if(sr_xpath_node_name_eq(new_val->xpath, + } else if(sr_xpath_node_name_eq(new->xpath, "loopback-mode")) { //TODO: LEAF: loopback-mode, type: boolean - } else if(sr_xpath_node_name_eq(new_val->xpath, + } else if(sr_xpath_node_name_eq(new->xpath, "description")) { //TODO: LEAF: description, type: string - } else if(sr_xpath_node_name_eq(new_val->xpath, "enabled")) { + } else if(sr_xpath_node_name_eq(new->xpath, "enabled")) { rc = interface_enable(interface_name, - new_val->data.bool_val); - } else if(sr_xpath_node_name_eq(new_val->xpath, + new->data.bool_val); + } else if(sr_xpath_node_name_eq(new->xpath, "oc-vlan:tpid")) { //TODO: LEAF: oc-vlan:tpid, type: identityref } @@ -139,21 +92,21 @@ int openconfig_interfaces_interfaces_interface_config_cb( break; case SR_OP_DELETED: - if (sr_xpath_node_name_eq(old_val->xpath, "name")) { + if (sr_xpath_node_name_eq(old->xpath, "name")) { //TODO: LEAF: name, type: string - } else if(sr_xpath_node_name_eq(old_val->xpath, "type")) { + } else if(sr_xpath_node_name_eq(old->xpath, "type")) { //TODO: LEAF: type, type: identityref - } else if(sr_xpath_node_name_eq(old_val->xpath, "mtu")) { + } else if(sr_xpath_node_name_eq(old->xpath, "mtu")) { //TODO: LEAF: mtu, type: uint16 - } else if(sr_xpath_node_name_eq(old_val->xpath, + } else if(sr_xpath_node_name_eq(old->xpath, "loopback-mode")) { //TODO: LEAF: loopback-mode, type: boolean - } else if(sr_xpath_node_name_eq(old_val->xpath, + } else if(sr_xpath_node_name_eq(old->xpath, "description")) { //TODO: LEAF: description, type: string - } else if(sr_xpath_node_name_eq(old_val->xpath, "enabled")) { + } else if(sr_xpath_node_name_eq(old->xpath, "enabled")) { rc = interface_enable(interface_name, false); - } else if(sr_xpath_node_name_eq(old_val->xpath, + } else if(sr_xpath_node_name_eq(old->xpath, "oc-vlan:tpid")) { //TODO: LEAF: oc-vlan:tpid, type: identityref } @@ -163,8 +116,8 @@ int openconfig_interfaces_interfaces_interface_config_cb( if (0 != rc) { sr_xpath_recover(&state); - sr_free_val(old_val); - sr_free_val(new_val); + sr_free_val(old); + sr_free_val(new); sr_free_change_iter(it); @@ -173,175 +126,190 @@ int openconfig_interfaces_interfaces_interface_config_cb( sr_xpath_recover(&state); - sr_free_val(old_val); - sr_free_val(new_val); + sr_free_val(old); + sr_free_val(new); } sr_free_change_iter(it); return SR_ERR_OK; } -// openconfig-interfaces -int openconfig_interface_mod_cb( - __attribute__((unused)) sr_session_ctx_t *session, - __attribute__((unused)) const char *module_name, - __attribute__((unused)) sr_notif_event_t event, - __attribute__((unused)) void *private_ctx) -{ - SRP_LOG_INF_MSG("In openconfig_interface_mod_cb"); - - return SR_ERR_OK; -} - -typedef struct +//XPATH : /openconfig-interfaces:interfaces/interface/state +static int +openconfig_interfaces_interfaces_interface_state_cb( + const char *xpath, sr_val_t **values, + size_t *values_cnt, uint64_t request_id, const char *original_xpath, + void *private_ctx) { - bool is_subif; - u32 subinterface_index; - sw_interface_details_query_t sw_interface_details_query; - sysr_values_ctx_t sysr_values_ctx; -} sys_sw_interface_dump_ctx; + UNUSED(request_id); UNUSED(original_xpath); UNUSED(private_ctx); + sw_interface_dump_t reply = {0}; + sr_val_t *vals = NULL; + sr_xpath_ctx_t state = {0}; + char interface_name[VPP_INTFC_NAME_LEN] = {0}; + char xpath_root[XPATH_SIZE]; + int vc = 10; + char *tmp; + int rc; -#define NOT_AVAL "NA" + SRP_LOG_INF("In %s", __FUNCTION__); + ARG_CHECK3(SR_ERR_INVAL_ARG, xpath, values, values_cnt); -static int sw_interface_dump_cb_inner( - vapi_payload_sw_interface_details * reply, - sys_sw_interface_dump_ctx * dctx) -{ - sr_val_t *vals = NULL; - int rc = 0; - int vc = 0; + tmp = sr_xpath_key_value((char*) xpath, "interface", "name", &state); + if (!tmp) { + SRP_LOG_ERR_MSG("XPATH interface name not found"); + return SR_ERR_INVAL_ARG; + } + strncpy(interface_name, tmp, VPP_INTFC_NAME_LEN); + sr_xpath_recover(&state); - ARG_CHECK2(SR_ERR_INVAL_ARG, reply, dctx); + snprintf(xpath_root, XPATH_SIZE, + "/openconfig-interfaces:interfaces/interface[name='%s']/state", + interface_name); - vc = 10; + //dump interface interface_name + rc = interface_dump_iface(&reply, interface_name); + if (rc == -SCVPP_NOT_FOUND) { + SRP_LOG_ERR_MSG("interface not found"); + return SR_ERR_NOT_FOUND; + } - /* convenient functions such as this can be found in sysrepo/values.h */ rc = sr_new_values(vc, &vals); - if (SR_ERR_OK != rc) { + if (SR_ERR_OK != rc) return rc; - } - - const char* interface_name = (const char*)dctx->sw_interface_details_query.sw_interface_details.interface_name; - sr_val_build_xpath(&vals[0], "%s/name", dctx->sysr_values_ctx.xpath_root); - sr_val_set_str_data(&vals[0], SR_STRING_T, interface_name); + sr_val_build_xpath(&vals[0], "%s/name", xpath_root); + sr_val_set_str_data(&vals[0], SR_STRING_T, (char *)reply.interface_name); - sr_val_build_xpath(&vals[1], "%s/type", dctx->sysr_values_ctx.xpath_root); + sr_val_build_xpath(&vals[1], "%s/type", xpath_root); sr_val_set_str_data(&vals[1], SR_IDENTITYREF_T, "ianaift:ethernetCsmacd"); - sr_val_build_xpath(&vals[2], "%s/mtu", dctx->sysr_values_ctx.xpath_root); + sr_val_build_xpath(&vals[2], "%s/mtu", xpath_root); vals[2].type = SR_UINT16_T; - vals[2].data.uint16_val = reply->link_mtu; + vals[2].data.uint16_val = reply.link_mtu; - sr_val_build_xpath(&vals[3], "%s/loopback-mode", - dctx->sysr_values_ctx.xpath_root); + sr_val_build_xpath(&vals[3], "%s/loopback-mode", xpath_root); vals[3].type = SR_BOOL_T; - vals[3].data.bool_val = (0 == strncmp(interface_name, "loop", 4)) ? 1 : 0; + if (strncmp((char*)reply.interface_name, "loop", 4) == 0) + vals[3].data.bool_val = 1; + else + vals[3].data.bool_val = 0; - sr_val_build_xpath(&vals[4], "%s/description", - dctx->sysr_values_ctx.xpath_root); + sr_val_build_xpath(&vals[4], "%s/description", xpath_root); sr_val_set_str_data(&vals[4], SR_STRING_T, NOT_AVAL); - sr_val_build_xpath(&vals[5], "%s/enabled", - dctx->sysr_values_ctx.xpath_root); + sr_val_build_xpath(&vals[5], "%s/enabled", xpath_root); vals[5].type = SR_BOOL_T; - vals[5].data.bool_val = reply->admin_up_down; + vals[5].data.bool_val = reply.admin_up_down; - sr_val_build_xpath(&vals[6], "%s/ifindex", - dctx->sysr_values_ctx.xpath_root); + sr_val_build_xpath(&vals[6], "%s/ifindex", xpath_root); vals[6].type = SR_UINT32_T; - vals[6].data.uint32_val = reply->sw_if_index; + vals[6].data.uint32_val = reply.sw_if_index; - sr_val_build_xpath(&vals[7], "%s/admin-status", - dctx->sysr_values_ctx.xpath_root); + sr_val_build_xpath(&vals[7], "%s/admin-status", xpath_root); sr_val_set_str_data(&vals[7], SR_ENUM_T, - reply->admin_up_down ? "UP" : "DOWN"); + reply.admin_up_down ? "UP" : "DOWN"); - sr_val_build_xpath(&vals[8], "%s/oper-status", - dctx->sysr_values_ctx.xpath_root); + sr_val_build_xpath(&vals[8], "%s/oper-status", xpath_root); sr_val_set_str_data(&vals[8], SR_ENUM_T, - reply->link_up_down ? "UP" : "DOWN"); + reply.link_up_down ? "UP" : "DOWN"); //TODO: Openconfig required this value - // sr_val_build_xpath(&vals[9], "%s/last-change", dctx->sysr_values_ctx.xpath_root); + // sr_val_build_xpath(&vals[9], "%s/last-change", xpath_root); // sr_val_set_str_data(&vals[9], YANG INPUT TYPE: oc-types:timeticks64); - sr_val_build_xpath(&vals[9], "%s/logical", - dctx->sysr_values_ctx.xpath_root); + sr_val_build_xpath(&vals[9], "%s/logical", xpath_root); vals[9].type = SR_BOOL_T; - vals[9].data.bool_val = true; //for now, we assume all are logical + vals[9].data.bool_val = true; //for now, we assume all are logical - dctx->sysr_values_ctx.values = vals; - dctx->sysr_values_ctx.values_cnt = vc; + *values = vals; + *values_cnt = vc; return SR_ERR_OK; } -static int sw_subinterface_dump_cb_inner( - vapi_payload_sw_interface_details *reply, - sys_sw_interface_dump_ctx *dctx) +//TODO: for some arcane reason, this doesn't work +static int openconfig_interfaces_interfaces_interface_subinterfaces_subinterface_oc_ip_ipv4_oc_ip_addresses_oc_ip_address_oc_ip_state_cb( + const char *xpath, sr_val_t **values, size_t *values_cnt, + uint64_t request_id, const char *original_xpath, void *private_ctx) { + UNUSED(request_id); UNUSED(original_xpath); UNUSED(private_ctx); + char xpath_root[XPATH_SIZE] = {0}; + sr_xpath_ctx_t state = {0}; sr_val_t *vals = NULL; - int rc = 0; - int vc = 0, val_idx = 0; + char interface_name[VPP_INTFC_NAME_LEN] = {0}; + char subinterface_index[XPATH_SIZE] = {0}; + char address_ip[XPATH_SIZE] = {0}; + u8 prefix_len; + char *tmp = NULL; + int rc, cnt = 0; - ARG_CHECK2(SR_ERR_INVAL_ARG, reply, dctx); + ARG_CHECK3(SR_ERR_INVAL_ARG, xpath, values, values_cnt); - vc = 6; - /* convenient functions such as this can be found in sysrepo/values.h */ - rc = sr_new_values(vc, &vals); - if (SR_ERR_OK != rc) { - return rc; + SRP_LOG_INF("In %s", __FUNCTION__); + + /* Get XPATH parameters name, index and ip */ + + tmp = sr_xpath_key_value((char*)xpath, "interface", "name", &state); + if (!tmp) { + SRP_LOG_ERR_MSG("XPATH interface name not found"); + return SR_ERR_INVAL_ARG; } + strncpy(interface_name, tmp, VPP_INTFC_NAME_LEN); + sr_xpath_recover(&state); - sr_val_build_xpath(&vals[val_idx], "%s/index", - dctx->sysr_values_ctx.xpath_root); - vals[val_idx].type = SR_UINT32_T; - vals[val_idx++].data.uint32_val = dctx->subinterface_index; + tmp = sr_xpath_key_value((char*)xpath, "subinterface", "index", &state); + if (NULL == tmp) { + SRP_LOG_ERR_MSG("XPATH subinterface index not found."); + return SR_ERR_INVAL_ARG; + } + strncpy(subinterface_index, tmp, XPATH_SIZE); + sr_xpath_recover(&state); - sr_val_build_xpath(&vals[val_idx], "%s/description", - dctx->sysr_values_ctx.xpath_root); - sr_val_set_str_data(&vals[val_idx++], SR_STRING_T, NOT_AVAL); + tmp = sr_xpath_key_value((char*)xpath, "address", "ip", &state); + if (NULL == tmp) { + SRP_LOG_ERR_MSG("XPATH address ip not found."); + return SR_ERR_INVAL_ARG; + } + strncpy(address_ip, tmp, XPATH_SIZE); + sr_xpath_recover(&state); - sr_val_build_xpath(&vals[val_idx], "%s/enabled", - dctx->sysr_values_ctx.xpath_root); - vals[val_idx].type = SR_BOOL_T; - vals[val_idx++].data.bool_val = reply->admin_up_down; + snprintf(xpath_root, XPATH_SIZE, "/openconfig-interfaces:interfaces/interface[name='%s']/subinterfaces/subinterface[index='%s']/openconfig-if-ip:ipv4/openconfig-if-ip:addresses/openconfig-if-ip:address[ip='%s']/openconfig-if-ip:state", + interface_name, subinterface_index, address_ip); - //TODO: Openconfig required this value - // sr_val_build_xpath(&vals[val_idx], "%s/name", dctx->sysr_values_ctx.xpath_root); - // sr_val_set_str_data(&vals[val_idx++], SR_STRING_T, YANG INPUT TYPE: string); + rc = ipv46_address_dump(interface_name, address_ip, &prefix_len, false); + if (!rc) { + SRP_LOG_ERR_MSG("ipv46_address_dump failed"); + return SR_ERR_INVAL_ARG; + } - // sr_val_build_xpath(&vals[val_idx], "%s/ifindex", interface_name, subinterface_index); - // vals[val_idx].type = SR_UINT32_T; - // vals[val_idx++].data.uint32_val = YANG INPUT TYPE: uint32; + /* Build answer to state XPATH */ - sr_val_build_xpath(&vals[val_idx], "%s/admin-status", - dctx->sysr_values_ctx.xpath_root); - sr_val_set_str_data(&vals[val_idx++], SR_ENUM_T, - reply->admin_up_down ? "UP" : "DOWN"); + rc = sr_new_values(3, &vals); + if (SR_ERR_OK != rc) + return rc; - sr_val_build_xpath(&vals[val_idx], "%s/oper-status", - dctx->sysr_values_ctx.xpath_root); - sr_val_set_str_data(&vals[val_idx++], SR_ENUM_T, - reply->admin_up_down ? "UP" : "DOWN"); + sr_val_build_xpath(&vals[cnt], "%s/openconfig-if-ip:ip", xpath_root); + sr_val_set_str_data(&vals[cnt], SR_STRING_T, address_ip); + cnt++; - //TODO: Openconfig required this value - // sr_val_build_xpath(&vals[val_idx], "/openconfig-interfaces:interfaces/interface[name='%s']/subinterfaces/subinterface[index='%s']/state/last-change", interface_name, subinterface_index); - // sr_val_set_str_data(&vals[val_idx++], YANG INPUT TYPE: oc-types:timeticks64); + sr_val_build_xpath(&vals[cnt], "%s/openconfig-if-ip:prefix-length", xpath_root); + vals[cnt].type = SR_UINT8_T; + vals[cnt].data.uint8_val = prefix_len; + cnt++; - sr_val_build_xpath(&vals[val_idx], "%s/logical", - dctx->sysr_values_ctx.xpath_root); - vals[val_idx].type = SR_BOOL_T; - vals[val_idx++].data.bool_val = true; //for now, we assume all are logical + sr_val_build_xpath(&vals[cnt], "%s/openconfig-if-ip:origin", xpath_root); + sr_val_set_str_data(&vals[cnt], SR_ENUM_T, "STATIC"); + cnt++; - dctx->sysr_values_ctx.values = vals; - dctx->sysr_values_ctx.values_cnt = vc; + sr_xpath_recover(&state); + *values = vals; + *values_cnt = cnt; return SR_ERR_OK; } +/* TODO move to common functions between all plugins */ static bool is_subinterface(const char* subif_name, const char* base_name, const u32 subif_index) @@ -351,11 +319,10 @@ is_subinterface(const char* subif_name, const char* base_name, const char* dot = strchr(subif_name, '.'); if (NULL == dot && 0 == subif_index) - return true; //subif_index == 0 can pass as a "real" interface + return true; //subif_index == 0 can pass as a "real" interface if (dot > subif_name && 0 == strncmp(subif_name, base_name, - dot - subif_name)) - { + dot - subif_name)) { char * eptr = NULL; u32 si = strtoul(dot + 1, &eptr, 10); @@ -366,289 +333,126 @@ is_subinterface(const char* subif_name, const char* base_name, return false; } -static vapi_error_e -sw_interface_dump_vapi_cb(struct vapi_ctx_s *ctx, void *callback_ctx, - vapi_error_e rv, bool is_last, - vapi_payload_sw_interface_details * reply) -{ - ARG_CHECK(VAPI_EINVAL, callback_ctx); - - if (is_last) - { - assert (NULL == reply); - } - else - { - assert (NULL != reply); - sys_sw_interface_dump_ctx *dctx = callback_ctx; - - const char* const dctx_interface_name = (const char *)dctx->sw_interface_details_query.sw_interface_details.interface_name; - - SRP_LOG_DBG("interface_name: '%s', if_name: '%s'", reply->interface_name, dctx_interface_name); - - if (dctx->is_subif) - { - if (is_subinterface((const char*)reply->interface_name, - dctx_interface_name, dctx->subinterface_index)) - sw_subinterface_dump_cb_inner(reply, dctx); - } - else - { - if (0 == strcmp(dctx_interface_name, (char *)reply->interface_name)) - { - dctx->sw_interface_details_query.sw_interface_details = *reply; - dctx->sw_interface_details_query.interface_found = true; - - sw_interface_dump_cb_inner(reply, dctx); - } - } - } - - return VAPI_OK; -} - -static vapi_error_e sysr_sw_interface_dump(sys_sw_interface_dump_ctx * dctx) -{ - vapi_msg_sw_interface_dump *dump; - vapi_error_e rv; - - ARG_CHECK(VAPI_EINVAL, dctx); - - dump = vapi_alloc_sw_interface_dump(g_vapi_ctx_instance); - - dump->payload.name_filter_valid = true; - strcpy((char*)dump->payload.name_filter, (const char *)dctx->sw_interface_details_query.sw_interface_details.interface_name); - - VAPI_CALL(vapi_sw_interface_dump(g_vapi_ctx_instance, dump, sw_interface_dump_vapi_cb, - dctx)); - - if (VAPI_OK != rv) { - SRP_LOG_DBG("vapi_sw_interface_dump error=%d", rv); - } - - return rv; -} - -int openconfig_interfaces_interfaces_interface_state_cb( - const char *xpath, sr_val_t **values, - size_t *values_cnt, - __attribute__((unused)) uint64_t request_id, - __attribute__((unused)) const char *original_xpath, - __attribute__((unused)) void *private_ctx) -{ - sr_xpath_ctx_t state = {0}; - char *tmp = NULL; - char interface_name[XPATH_SIZE] = {0}; - - SRP_LOG_INF_MSG("In openconfig_interfaces_interfaces_interface_state_cb"); - - ARG_CHECK3(SR_ERR_INVAL_ARG, xpath, values, values_cnt); - - tmp = xpath_find_first_key(xpath, "name", &state); - if (NULL == tmp) { - SRP_LOG_ERR_MSG("Interface name not found in sysrepo database"); - return SR_ERR_INVAL_ARG; - } - - strncpy(interface_name, tmp, XPATH_SIZE); - sr_xpath_recover(&state); - - sys_sw_interface_dump_ctx dctx = { - .is_subif = false - }; - sw_interface_details_query_set_name(&dctx.sw_interface_details_query, - interface_name); - - snprintf(dctx.sysr_values_ctx.xpath_root, XPATH_SIZE, - "/openconfig-interfaces:interfaces/interface[name='%s']/state", - interface_name); - - sysr_sw_interface_dump(&dctx); - - if (!dctx.sw_interface_details_query.interface_found) { - SRP_LOG_ERR_MSG("interface not found"); - return SR_ERR_NOT_FOUND; - } - - sr_xpath_recover(&state); - *values = dctx.sysr_values_ctx.values; - *values_cnt = dctx.sysr_values_ctx.values_cnt; - - return SR_ERR_OK; -} - -int oc_dump_ip_helper(char *address_ip, u8 prefix_len, - sysr_values_ctx_t *sysr_values_ctx) -{ - sr_val_t *vals = NULL; - int rc = 0; - int vc = 0; - - ARG_CHECK2(SR_ERR_INVAL_ARG, address_ip, sysr_values_ctx); - - vc = 3; - /* convenient functions such as this can be found in sysrepo/values.h */ - rc = sr_new_values(vc, &vals); - if (SR_ERR_OK != rc) { - return rc; - } - - sr_val_build_xpath(&vals[0], "%s/openconfig-if-ip:ip", - sysr_values_ctx->xpath_root); - sr_val_set_str_data(&vals[0], SR_STRING_T, address_ip); - - sr_val_build_xpath(&vals[1], "%s/openconfig-if-ip:prefix-length", - sysr_values_ctx->xpath_root); - vals[1].type = SR_UINT8_T; - vals[1].data.uint8_val = prefix_len; - - sr_val_build_xpath(&vals[2], "%s/openconfig-if-ip:origin", - sysr_values_ctx->xpath_root); - sr_val_set_str_data(&vals[2], SR_ENUM_T, "STATIC"); - - sysr_values_ctx->values = vals; - sysr_values_ctx->values_cnt = vc; - - return SR_ERR_OK; -} - -//TODO: for some arcane reason, this doesn't work -int openconfig_interfaces_interfaces_interface_subinterfaces_subinterface_oc_ip_ipv4_oc_ip_addresses_oc_ip_address_oc_ip_state_cb( +// openconfig-interfaces:interfaces/interface/subinterfaces/subinterface/state +static int openconfig_interfaces_interfaces_interface_subinterfaces_subinterface_state_cb( const char *xpath, sr_val_t **values, size_t *values_cnt, - __attribute__((unused)) uint64_t request_id, - __attribute__((unused)) const char *original_xpath, - __attribute__((unused)) void *private_ctx) + uint64_t request_id, const char *original_xpath, void *private_ctx) { + UNUSED(request_id); UNUSED(original_xpath); UNUSED(private_ctx); + sw_interface_dump_t reply = {0}; + char xpath_root[XPATH_SIZE]; sr_xpath_ctx_t state = {0}; - int rc; char *tmp = NULL; - char interface_name[XPATH_SIZE] = {0}; + char interface_name[VPP_INTFC_NAME_LEN] = {0}; char subinterface_index[XPATH_SIZE] = {0}; - char address_ip[XPATH_SIZE] = {0}; - u8 prefix_len; + u32 sub_id; + sr_val_t *vals = NULL; + int vc = 6; + int val_idx = 0; + int rc; ARG_CHECK3(SR_ERR_INVAL_ARG, xpath, values, values_cnt); - SRP_LOG_INF_MSG("In oc-interfaces oc-ip"); + SRP_LOG_INF("In %s", __FUNCTION__); - tmp = xpath_find_first_key(xpath, "name", &state); - if (NULL == tmp) { - SRP_LOG_ERR_MSG("interface_name not found."); + tmp = sr_xpath_key_value((char*)xpath, "interface", "name", &state); + if (!tmp) { + SRP_LOG_ERR_MSG("XPATH interface name not found"); return SR_ERR_INVAL_ARG; } - - strncpy(interface_name, tmp, XPATH_SIZE); + strncpy(interface_name, tmp, VPP_INTFC_NAME_LEN); sr_xpath_recover(&state); - tmp = xpath_find_first_key(xpath, "index", &state); - if (NULL == tmp) { - SRP_LOG_ERR_MSG("subinterface_index not found."); + tmp = sr_xpath_key_value((char*)xpath, "subinterface", "index", &state); + if (!tmp) { + SRP_LOG_ERR_MSG("subinterface index not found"); return SR_ERR_INVAL_ARG; } - strncpy(subinterface_index, tmp, XPATH_SIZE); sr_xpath_recover(&state); - tmp = xpath_find_first_key(xpath, "ip", &state); - if (NULL == tmp) { - SRP_LOG_ERR_MSG("address_ip not found."); - return SR_ERR_INVAL_ARG; - } - - strncpy(address_ip, tmp, XPATH_SIZE); - sr_xpath_recover(&state); - - sysr_values_ctx_t dctx = {0}; - snprintf(dctx.xpath_root, XPATH_SIZE, "/openconfig-interfaces:interfaces/interface[name='%s']/subinterfaces/subinterface[index='%s']/openconfig-if-ip:ipv4/openconfig-if-ip:addresses/openconfig-if-ip:address[ip='%s']/openconfig-if-ip:state", - interface_name, subinterface_index, address_ip); + snprintf(xpath_root, XPATH_SIZE, + "/openconfig-interfaces:interfaces/interface[name='%s']/subinterfaces/subinterface[index='%s']/state", + interface_name, subinterface_index); - rc = ipv46_address_dump(interface_name, address_ip, &prefix_len, false); - if (!rc) { - SRP_LOG_ERR_MSG("ipv46_address_dump failed"); - return SR_ERR_INVAL_ARG; + rc = interface_dump_iface(&reply, interface_name); + if (rc == -SCVPP_NOT_FOUND) { + SRP_LOG_ERR_MSG("interface not found"); + return SR_ERR_NOT_FOUND; } - rc = oc_dump_ip_helper(address_ip, prefix_len, &dctx); - if (!rc) { - SRP_LOG_ERR_MSG("oc_dump_ip_helper failed"); - return rc; + /* Check that requested subinterface index matches reply subid */ + sub_id = atoi(subinterface_index); + if (sub_id != reply.sub_id) { + SRP_LOG_ERR_MSG("subinterface index not found."); + return SR_ERR_NOT_FOUND; } - sr_xpath_recover(&state); - *values = dctx.values; - *values_cnt = dctx.values_cnt; - - return SR_ERR_OK; -} + /* Check that interface is a sub interface */ + if (!is_subinterface((char*)reply.interface_name, interface_name, sub_id)) { + SRP_LOG_ERR("%s not a subinterface", interface_name); + return SR_ERR_OPERATION_FAILED; + } -// openconfig-interfaces:interfaces/interface/subinterfaces/subinterface/state -int openconfig_interfaces_interfaces_interface_subinterfaces_subinterface_state_cb( - const char *xpath, sr_val_t **values, size_t *values_cnt, - __attribute__((unused)) uint64_t request_id, - __attribute__((unused)) const char *original_xpath, - __attribute__((unused)) void *private_ctx) -{ - sr_xpath_ctx_t state = {0}; - char *tmp = NULL; - char interface_name[XPATH_SIZE] = {0}; - char subinterface_index[XPATH_SIZE] = {0}; + rc = sr_new_values(vc, &vals); + if (SR_ERR_OK != rc) + return rc; - ARG_CHECK3(SR_ERR_INVAL_ARG, xpath, values, values_cnt); + sr_val_build_xpath(&vals[val_idx], "%s/index", xpath_root); + vals[val_idx].type = SR_UINT32_T; + vals[val_idx++].data.uint32_val = sub_id; - tmp = xpath_find_first_key(xpath, "name", &state); - if (NULL == tmp) { - SRP_LOG_ERR_MSG("interface_name not found."); - return SR_ERR_INVAL_ARG; - } + sr_val_build_xpath(&vals[val_idx], "%s/description", xpath_root); + sr_val_set_str_data(&vals[val_idx++], SR_STRING_T, NOT_AVAL); - strncpy(interface_name, tmp, XPATH_SIZE); - sr_xpath_recover(&state); + sr_val_build_xpath(&vals[val_idx], "%s/enabled", xpath_root); + vals[val_idx].type = SR_BOOL_T; + vals[val_idx++].data.bool_val = reply.admin_up_down; - tmp = xpath_find_first_key(xpath, "index", &state); - if (NULL == tmp) { - SRP_LOG_ERR_MSG("subinterface_index not found."); - return SR_ERR_INVAL_ARG; - } + //TODO: Openconfig required this value + // sr_val_build_xpath(&vals[val_idx], "%s/name", xpath_root); + // sr_val_set_str_data(&vals[val_idx++], SR_STRING_T, YANG INPUT TYPE: string); - strncpy(subinterface_index, tmp, XPATH_SIZE); - sr_xpath_recover(&state); + // sr_val_build_xpath(&vals[val_idx], "%s/ifindex", interface_name, sub_id); + // vals[val_idx].type = SR_UINT32_T; + // vals[val_idx++].data.uint32_val = YANG INPUT TYPE: uint32; - sys_sw_interface_dump_ctx dctx = - { - .is_subif = true, - .subinterface_index = atoi(subinterface_index) - }; - sw_interface_details_query_set_name(&dctx.sw_interface_details_query, - interface_name); + sr_val_build_xpath(&vals[val_idx], "%s/admin-status", xpath_root); + sr_val_set_str_data(&vals[val_idx++], SR_ENUM_T, + reply.admin_up_down ? "UP" : "DOWN"); - snprintf(dctx.sysr_values_ctx.xpath_root, XPATH_SIZE, "/openconfig-interfaces:interfaces/interface[name='%s']/subinterfaces/subinterface[index='%s']/state", - interface_name, subinterface_index); + sr_val_build_xpath(&vals[val_idx], "%s/oper-status", xpath_root); + sr_val_set_str_data(&vals[val_idx++], SR_ENUM_T, reply.admin_up_down ? "UP" : "DOWN"); - sysr_sw_interface_dump(&dctx); + //TODO: Openconfig required this value + // sr_val_build_xpath(&vals[val_idx], "/openconfig-interfaces:interfaces/interface[name='%s']/subinterfaces/subinterface[index='%s']/state/last-change", interface_name, sub_id); + // sr_val_set_str_data(&vals[val_idx++], YANG INPUT TYPE: oc-types:timeticks64); - if (!dctx.sw_interface_details_query.interface_found) { - SRP_LOG_DBG_MSG("interface not found"); - return SR_ERR_NOT_FOUND; - } + sr_val_build_xpath(&vals[val_idx], "%s/logical", xpath_root); + vals[val_idx].type = SR_BOOL_T; + vals[val_idx++].data.bool_val = true; //for now, we assume all are logical sr_xpath_recover(&state); - *values = dctx.sysr_values_ctx.values; - *values_cnt = dctx.sysr_values_ctx.values_cnt; + + *values = vals; + *values_cnt = vc; return SR_ERR_OK; } // openconfig-interfaces:interfaces/interface[name='%s']/subinterfaces/subinterface[index='%s']/oc-ip:ipv4/oc-ip:addresses/oc-ip:address[ip='%s']/oc-ip:config/ -int openconfig_interfaces_interfaces_interface_subinterfaces_subinterface_oc_ip_ipv4_oc_ip_addresses_oc_ip_address_oc_ip_config_cb( +static int openconfig_interfaces_interfaces_interface_subinterfaces_subinterface_oc_ip_ipv4_oc_ip_addresses_oc_ip_address_oc_ip_config_cb( sr_session_ctx_t *ds, const char *xpath, sr_notif_event_t event, - __attribute__((unused)) void *private_ctx) + void *private_ctx) { + UNUSED(private_ctx); sr_change_iter_t *it = NULL; sr_change_oper_t oper; - sr_val_t *old_val = NULL; - sr_val_t *new_val = NULL; + sr_xpath_ctx_t state = {0}; + sr_val_t *old = NULL; + sr_val_t *new = NULL; char *tmp = NULL; - char interface_name[XPATH_SIZE] = {0}; + char interface_name[VPP_INTFC_NAME_LEN] = {0}; char subinterface_index[XPATH_SIZE] = {0}; char address_ip[XPATH_SIZE] = {0}; char old_address_ip[XPATH_SIZE] = {0}; @@ -662,82 +466,69 @@ int openconfig_interfaces_interfaces_interface_subinterfaces_subinterface_oc_ip_ // if we receive event SR_EV_APPLY - config has changed - log_recv_event(event, "subtree_change_cb received"); - SRP_LOG_DBG("[SRP_LOG_DBG] xpath: %s", xpath); - - if (event != SR_EV_APPLY) { + if (event == SR_EV_APPLY) return SR_ERR_OK; - } if (sr_get_changes_iter(ds, (char *)xpath, &it) != SR_ERR_OK) { - // in example he calls even on fale sr_free_change_iter(it); return SR_ERR_OK; } - while (sr_get_change_next(ds, it, &oper, &old_val, &new_val) == SR_ERR_OK) { - - log_recv_oper(oper, "subtree_change_cb received"); + foreach_change (ds, it, oper, old, new) { - SRP_LOG_DBG("xpath: %s", new_val->xpath); + SRP_LOG_DBG("xpath: %s", new->xpath); - sr_xpath_ctx_t state = {0}; - - tmp = xpath_find_first_key(new_val->xpath, "name", &state); - if (NULL == tmp) { - SRP_LOG_DBG_MSG("interface_name NOT found."); - continue; + tmp = sr_xpath_key_value(new->xpath, "interface", "name", &state); + if (!tmp) { + sr_set_error(ds, "XPATH interface name NOT found", new->xpath); + return SR_ERR_INVAL_ARG; } - - strncpy(interface_name, tmp, XPATH_SIZE); + strncpy(interface_name, tmp, VPP_INTFC_NAME_LEN); sr_xpath_recover(&state); - tmp = xpath_find_first_key(new_val->xpath, "index", &state); - if (NULL == tmp) { - SRP_LOG_DBG_MSG("subinterface_index NOT found."); - continue; + tmp = sr_xpath_key_value(new->xpath, "subinterface", "index", &state); + if (!tmp) { + sr_set_error(ds, "XPATH subinterface index NOT found", new->xpath); + return SR_ERR_INVAL_ARG; } - strncpy(subinterface_index, tmp, XPATH_SIZE); sr_xpath_recover(&state); switch (oper) { case SR_OP_CREATED: - if (sr_xpath_node_name_eq(new_val->xpath, "ip")) { + if (sr_xpath_node_name_eq(new->xpath, "ip")) { ip_set = true; - strncpy(address_ip, new_val->data.string_val, XPATH_SIZE); - } else if (sr_xpath_node_name_eq(new_val->xpath, + strncpy(address_ip, new->data.string_val, XPATH_SIZE); + } else if (sr_xpath_node_name_eq(new->xpath, "prefix-length")) { prefix_len_set = true; - prefix_len = new_val->data.uint8_val; + prefix_len = new->data.uint8_val; } - if (ip_set && prefix_len_set) { - //add ipv4 + if (ip_set && prefix_len_set) //add ipv4 rc = ipv46_config_add_remove(interface_name, address_ip, prefix_len, false , true); - } break; case SR_OP_MODIFIED: - if (sr_xpath_node_name_eq(old_val->xpath, "ip")) { + if (sr_xpath_node_name_eq(old->xpath, "ip")) { old_ip_set = true; - strncpy(old_address_ip, old_val->data.string_val, + strncpy(old_address_ip, old->data.string_val, XPATH_SIZE); - } else if (sr_xpath_node_name_eq(old_val->xpath, + } else if (sr_xpath_node_name_eq(old->xpath, " prefix-length")) { old_prefix_len_set = true; - old_prefix_len = old_val->data.uint8_val; + old_prefix_len = old->data.uint8_val; } - if (sr_xpath_node_name_eq(new_val->xpath, "ip")) { + if (sr_xpath_node_name_eq(new->xpath, "ip")) { ip_set = true; - strncpy(address_ip, new_val->data.string_val, XPATH_SIZE); - } else if (sr_xpath_node_name_eq(new_val->xpath, + strncpy(address_ip, new->data.string_val, XPATH_SIZE); + } else if (sr_xpath_node_name_eq(new->xpath, "prefix-length")) { prefix_len_set = true; - prefix_len = new_val->data.uint8_val; + prefix_len = new->data.uint8_val; } if (old_ip_set && old_prefix_len_set) { @@ -760,14 +551,14 @@ int openconfig_interfaces_interfaces_interface_subinterfaces_subinterface_oc_ip_ break; case SR_OP_DELETED: - if (sr_xpath_node_name_eq(old_val->xpath, "ip")) { + if (sr_xpath_node_name_eq(old->xpath, "ip")) { old_ip_set = true; - strncpy(old_address_ip, old_val->data.string_val, + strncpy(old_address_ip, old->data.string_val, XPATH_SIZE); - } else if (sr_xpath_node_name_eq(old_val->xpath, + } else if (sr_xpath_node_name_eq(old->xpath, "prefix-length")) { old_prefix_len_set = true; - old_prefix_len = old_val->data.uint8_val; + old_prefix_len = old->data.uint8_val; } if (old_ip_set && old_prefix_len_set) { @@ -781,8 +572,8 @@ int openconfig_interfaces_interfaces_interface_subinterfaces_subinterface_oc_ip_ if (0 != rc) { sr_xpath_recover(&state); - sr_free_val(old_val); - sr_free_val(new_val); + sr_free_val(old); + sr_free_val(new); sr_free_change_iter(it); @@ -791,8 +582,8 @@ int openconfig_interfaces_interfaces_interface_subinterfaces_subinterface_oc_ip_ sr_xpath_recover(&state); - sr_free_val(old_val); - sr_free_val(new_val); + sr_free_val(old); + sr_free_val(new); } sr_free_change_iter(it); @@ -801,16 +592,6 @@ int openconfig_interfaces_interfaces_interface_subinterfaces_subinterface_oc_ip_ const xpath_t oc_interfaces_xpaths[OC_INTERFACES_SIZE] = { { - .xpath = "openconfig-interfaces", - .method = MODULE, - .datastore = SR_DS_RUNNING, - .cb.mcb = openconfig_interface_mod_cb, - .private_ctx = NULL, - .priority = 0, - //.opts = SR_SUBSCR_EV_ENABLED | SR_SUBSCR_APPLY_ONLY - .opts = SR_SUBSCR_EV_ENABLED | SR_SUBSCR_APPLY_ONLY | SR_SUBSCR_CTX_REUSE - }, - { .xpath = "/openconfig-interfaces:interfaces/interface/config", .method = XPATH, .datastore = SR_DS_RUNNING, diff --git a/src/plugins/openconfig/openconfig_interfaces.h b/src/plugins/openconfig/openconfig_interfaces.h deleted file mode 100644 index 88d5fe0..0000000 --- a/src/plugins/openconfig/openconfig_interfaces.h +++ /dev/null @@ -1,26 +0,0 @@ -/* - * Copyright (c) 2018 PANTHEON.tech. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at: - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - -#ifndef __OPENCONFIG_INTERFACES_H__ -#define __OPENCONFIG_INTERFACES_H__ - -#include "../sc_model.h" - -#define OC_INTERFACES_SIZE 6 -extern const xpath_t oc_interfaces_xpaths[OC_INTERFACES_SIZE]; - -#endif /* __OPENCONFIG_INTERFACES_H__ */ diff --git a/src/plugins/openconfig/openconfig_local_routing.c b/src/plugins/openconfig/openconfig_local_routing.c index 5c63eaa..5d18b52 100644 --- a/src/plugins/openconfig/openconfig_local_routing.c +++ b/src/plugins/openconfig/openconfig_local_routing.c @@ -17,732 +17,494 @@ #include <assert.h> #include <string.h> -#include "openconfig_local_routing.h" +#include <scvpp/comm.h> +#include <scvpp/interface.h> +#include <scvpp/ip.h> +#include "../sc_model.h" #include "../sys_util.h" -#include "sc_vpp_comm.h" -#include "sc_vpp_interface.h" -#include "sc_vpp_ip.h" +#define HOP_INDEX_SIZE 10 //number of digit in max 32 bit integer -#define XPATH_SIZE 2000 - -int openconfig_local_routing_mod_cb( - __attribute__((unused)) sr_session_ctx_t* session, - __attribute__((unused)) const char* module_name, - __attribute__((unused)) sr_notif_event_t event, - __attribute__((unused)) void* private_ctx) +static inline int +_set_route (const char *prefix, const char *nhop, bool is_add, + const char *iface) { - SRP_LOG_DBG("Local routing module subscribe: %s", module_name); + int table = 0; //FIB table ID + int mask; + int rc; + + // Put prefix length in mask and prefix IP in prefix + mask = ip_prefix_split(prefix); + if (mask < 1) { + SRP_LOG_ERR("Prefix length can not be %d", mask); + return SR_ERR_INVAL_ARG; + } + + rc = ipv46_config_add_del_route(prefix, mask, nhop, is_add, table, iface); + if (rc != SCVPP_OK) { + SRP_LOG_ERR("Add/delete route failed for %s %s", prefix, iface); + return SR_ERR_INVAL_ARG; + } + + SRP_LOG_INF("Add/delete route Success for %s %s", prefix, iface); return SR_ERR_OK; } -static int set_route(sr_session_ctx_t *sess, const char *index, - const char *n_interface /*NULLABLE*/, - const char *n_next_hop /*NULLABLE*/, - const char *prefix, bool is_add) -{ - int rc = SR_ERR_OK; - sr_val_t *value = NULL; - char xpath[XPATH_SIZE] = {0}; - const char *interface = NULL; - const char *next_hop = NULL; +#define STR(string) #string - ARG_CHECK3(SR_ERR_INVAL_ARG, sess, index, prefix); +#define ROOT "/openconfig-local-routing:local-routes/static-routes/static[prefix='%s']/next-hops/next-hop[index='%s']/%s" - if (NULL == n_interface) { - snprintf(xpath, XPATH_SIZE, - "/openconfig-local-routing:local-routes/static-routes/static[prefix='%s']/next-hops/next-hop[index='%s']/interface-ref/config/interface", prefix, index); +static inline char * _get_ds_elem(sr_session_ctx_t *sess, const char *prefix, + const char *index, const char *sub) +{ + char xpath[XPATH_SIZE] = {0}; + sr_val_t *value = NULL; + int rc; - rc = sr_get_item(sess, xpath, &value); - if (SR_ERR_OK != rc) { - SRP_LOG_DBG_MSG("Interface not set"); - return 0; - } + snprintf(xpath, XPATH_SIZE, ROOT, prefix, index, sub); - interface = value->data.string_val; - } else { - interface = n_interface; + rc = sr_get_item(sess, xpath, &value); + if (SR_ERR_OK != rc) { + SRP_LOG_DBG("XPATH %s not set", xpath); + return NULL; } - if (NULL == n_next_hop) { - snprintf(xpath, XPATH_SIZE, - "/openconfig-local-routing:local-routes/static-routes/static[prefix='%s']/next-hops/next-hop[index='%s']/config/next-hop", prefix, index); + return value->data.string_val; +} - rc = sr_get_item(sess, xpath, &value); - if (SR_ERR_OK != rc) { - SRP_LOG_DBG_MSG("Next-hop not set"); - return 0; - } +/* @brief add/del route to FIB table 0. + * If you add/delete an entry to FIB, prefix is mandatory and next hop can be: + * - interface only + * - next hop IP + * - both interface and next hop IP + */ +static int set_route(sr_session_ctx_t *sess, const char *index, + const char *interface /* NULLABLE*/, + const char *next_hop /* NULLABLE*/, + const char *prefix, bool is_add) +{ + const char *iface = NULL; + const char *nhop = NULL; - next_hop = value->data.string_val; - } else { - next_hop = n_next_hop; - } + ARG_CHECK3(SR_ERR_INVAL_ARG, sess, index, prefix); - int mask = ip_prefix_split(prefix); - if (mask < 1) { + if (!interface && !next_hop) return SR_ERR_INVAL_ARG; - } - rc = ipv46_config_add_del_route(prefix, mask, next_hop, is_add, 0, - interface); - if (!rc) { - return SR_ERR_INVAL_ARG; - } + if (!interface) //fetch interface in datastore, can return NULL + iface = _get_ds_elem(sess, prefix, index, "interface-ref/config/interface"); + else //use interface provided + iface = interface; + + if (!next_hop) //fetch next-hop in datastore , can return NULL + nhop = _get_ds_elem(sess, prefix, index, "config/next-hop"); + else //use next hop IP provided + nhop = next_hop; + + return _set_route(prefix, nhop, is_add, iface); +} + +/* @brief Callback used to add prefix entry for XPATH: + * /openconfig-local-routing:local-routes/static-routes/static/config + */ +static int +oc_prefix_config_cb(sr_session_ctx_t *ds, const char *xpath, + sr_notif_event_t event, void *private_ctx) +{ + UNUSED(ds); UNUSED(xpath); UNUSED(event); UNUSED(private_ctx); + + SRP_LOG_INF("In %s", __FUNCTION__); return SR_ERR_OK; } // XPATH: /openconfig-local-routing:local-routes/static-routes/static[prefix='%s']/next-hops/next-hop[index='%s']/config/ -int openconfig_local_routing_local_routes_static_routes_static_next_hops_next_hop_config_cb( - sr_session_ctx_t *ds, const char *xpath, sr_notif_event_t event, - __attribute__((unused)) void *private_ctx) +static int oc_next_hop_config_cb(sr_session_ctx_t *ds, const char *xpath, + sr_notif_event_t event, void *private_ctx) { - sr_change_iter_t *it = NULL; + char prefix[VPP_IP4_PREFIX_STRING_LEN] = {0}; + char next_hop[VPP_IP4_ADDRESS_STRING_LEN] = {0}; //IP of next router + char index[HOP_INDEX_SIZE]; //next hop index + bool index_set = false, next_hop_set = false; + sr_change_iter_t *it; sr_change_oper_t oper; - sr_val_t *old_val = NULL; - sr_val_t *new_val = NULL; + sr_val_t *old, *new, *tmp; + sr_xpath_ctx_t state = {0}; int rc = SR_ERR_OK; - char *tmp = NULL; - char static_prefix[XPATH_SIZE] = {0}; - char next_hop_index[XPATH_SIZE] = {0}; - char next_hop[XPATH_SIZE] = {0}; - char old_next_hop_index[XPATH_SIZE] = {0}; - char old_next_hop[XPATH_SIZE] = {0}; - bool index_set = false, next_hop_set = false; - bool old_index_set = false, old_next_hop_set = false; + UNUSED(private_ctx); ARG_CHECK2(SR_ERR_INVAL_ARG, ds, xpath); - // if we receive event SR_EV_APPLY - config has changed + SRP_LOG_INF("In %s", __FUNCTION__); - log_recv_event(event, "subtree_change_cb received"); - SRP_LOG_DBG("[SRP_LOG_DBG] xpath: %s", xpath); - - if (event != SR_EV_APPLY) { + if (event == SR_EV_APPLY) //SR_EV_VERIFY already applied the changes return SR_ERR_OK; - } - if (sr_get_changes_iter(ds, (char *)xpath, &it) != SR_ERR_OK) { - // in example he calls even on fale + rc = sr_get_changes_iter(ds, (char *)xpath, &it); + if (rc != SR_ERR_OK) { sr_free_change_iter(it); - return SR_ERR_OK; + return rc; } - while (sr_get_change_next(ds, it, &oper, - &old_val, &new_val) == SR_ERR_OK) { - - log_recv_oper(oper, "subtree_change_cb received"); - - SRP_LOG_DBG("xpath: %s", new_val->xpath); - - sr_xpath_ctx_t state = {0}; - - tmp = xpath_find_first_key(new_val->xpath, "prefix", &state); - if (NULL == tmp) { - SRP_LOG_DBG_MSG("static_prefix NOT found."); - continue; - } + foreach_change(ds, it, oper, old, new) { - strncpy(static_prefix, tmp, XPATH_SIZE); - sr_xpath_recover(&state); + rc = get_xpath_key(prefix, new->xpath, "static", "prefix", + VPP_IP4_PREFIX_STRING_LEN, &state); + if (rc != 0) + goto error; switch (oper) { - case SR_OP_CREATED: - if (sr_xpath_node_name_eq(new_val->xpath, "index")) { - strncpy(next_hop_index, new_val->data.string_val, - XPATH_SIZE); - index_set = true; - } else if(sr_xpath_node_name_eq(new_val->xpath, "next-hop")) { - next_hop_set = true; - strncpy(next_hop, new_val->data.string_val, XPATH_SIZE); - } else if(sr_xpath_node_name_eq(new_val->xpath, "metric")) { - //TODO: LEAF: metric, type: uint32 - } else if(sr_xpath_node_name_eq(new_val->xpath, "recurse")) { - //TODO: LEAF: recurse, type: boolean - } - - if (index_set && next_hop_set) { - rc = set_route(ds, next_hop_index, NULL, next_hop, - static_prefix, true); - } - break; - case SR_OP_MODIFIED: - if (sr_xpath_node_name_eq(old_val->xpath, "index")) { - strncpy(old_next_hop_index, old_val->data.string_val, - XPATH_SIZE); - old_index_set = true; - } else if(sr_xpath_node_name_eq(old_val->xpath, "next-hop")) { - old_next_hop_set = true; - strncpy(old_next_hop, old_val->data.string_val, XPATH_SIZE); - } else if(sr_xpath_node_name_eq(old_val->xpath, "metric")) { - //TODO: LEAF: metric, type: uint32 - } else if(sr_xpath_node_name_eq(old_val->xpath, "recurse")) { - //TODO: LEAF: recurse, type: boolean - } - - if (sr_xpath_node_name_eq(new_val->xpath, "index")) { - strncpy(next_hop_index, new_val->data.string_val, - XPATH_SIZE); - index_set = true; - } else if(sr_xpath_node_name_eq(new_val->xpath, "next-hop")) { - next_hop_set = true; - strncpy(next_hop, new_val->data.string_val, XPATH_SIZE); - } else if(sr_xpath_node_name_eq(new_val->xpath, "metric")) { - //TODO: LEAF: metric, type: uint32 - } else if(sr_xpath_node_name_eq(new_val->xpath, "recurse")) { - //TODO: LEAF: recurse, type: boolean - } - - if (old_index_set && old_next_hop_set) { - rc = set_route(ds, old_next_hop_index, NULL, old_next_hop, - static_prefix, false); - } - - if (index_set && next_hop_set) { - rc = set_route(ds, next_hop_index, NULL, next_hop, - static_prefix, true); - } - break; - - case SR_OP_MOVED: + case SR_OP_CREATED: + tmp = new; break; - case SR_OP_DELETED: - if (sr_xpath_node_name_eq(old_val->xpath, "index")) { - strncpy(old_next_hop_index, old_val->data.string_val, - XPATH_SIZE); - old_index_set = true; - } else if(sr_xpath_node_name_eq(old_val->xpath, "next-hop")) { - old_next_hop_set = true; - strncpy(old_next_hop, old_val->data.string_val, XPATH_SIZE); - } else if(sr_xpath_node_name_eq(old_val->xpath, "metric")) { - //TODO: LEAF: metric, type: uint32 - } else if(sr_xpath_node_name_eq(old_val->xpath, "recurse")) { - //TODO: LEAF: recurse, type: boolean - } - - if (old_index_set && old_next_hop_set) { - rc = set_route(ds, old_next_hop_index, NULL, old_next_hop, - static_prefix, false); - } + tmp = old; + break; + default: + SRP_LOG_WRN_MSG("Operation not supported"); break; } - if (SR_ERR_OK != rc) { - sr_xpath_recover(&state); + if (sr_xpath_node_name_eq(tmp->xpath, "config")) { + SRP_LOG_DBG("xpath: %s", tmp->xpath); + } else if (sr_xpath_node_name_eq(tmp->xpath, "index")) { + strncpy(index, tmp->data.string_val, HOP_INDEX_SIZE); + index_set = true; + } else if(sr_xpath_node_name_eq(tmp->xpath, "next-hop")) { + strncpy(next_hop, tmp->data.string_val, VPP_IP4_ADDRESS_STRING_LEN); + next_hop_set = true; + } else if(sr_xpath_node_name_eq(tmp->xpath, "recurse")) { + //SYSREPO BUG: Just catch it, sysrepo thinks it is mandatory... + } else { //metric, recurse + SRP_LOG_ERR("Unsupported field %s", tmp->xpath); + return SR_ERR_UNSUPPORTED; + } - sr_free_val(old_val); - sr_free_val(new_val); + if (index_set && next_hop_set) { + if (oper == SR_OP_CREATED) { + rc = set_route(ds, index, NULL, next_hop, prefix, true); + } else if (oper == SR_OP_MODIFIED) { + rc = set_route(ds, index, NULL, next_hop, prefix, false); + rc |= set_route(ds, index, NULL, next_hop, prefix, true); + } else if (oper == SR_OP_DELETED) { + rc = set_route(ds, index, NULL, next_hop, prefix, false); + } - sr_free_change_iter(it); - return SR_ERR_OPERATION_FAILED; + if (rc != 0) { + SRP_LOG_ERR_MSG("setting route failed"); + goto error; + } + index_set = false; next_hop_set = false; } + sr_free_val(old); + sr_free_val(new); sr_xpath_recover(&state); - - sr_free_val(old_val); - sr_free_val(new_val); } sr_free_change_iter(it); - return SR_ERR_OK; + return rc; + +error: + sr_free_val(old); + sr_free_val(new); + sr_xpath_recover(&state); + sr_free_change_iter(it); + return rc; } // XPATH: /openconfig-local-routing:local-routes/static-routes/static[prefix='%s']/next-hops/next-hop[index='%s']/interface-ref/config/ -int openconfig_local_routing_local_routes_static_routes_static_next_hops_next_hop_interface_ref_config_cb( - sr_session_ctx_t *ds, const char *xpath, sr_notif_event_t event, - __attribute__((unused)) void *private_ctx) +static int +oc_next_hop_interface_config_cb(sr_session_ctx_t *ds, const char *xpath, + sr_notif_event_t event, void *private_ctx) { + char prefix[VPP_IP4_PREFIX_STRING_LEN] = {0}; + char interface[VPP_INTFC_NAME_LEN] = {0}; + char index[HOP_INDEX_SIZE] = {0}; sr_change_iter_t *it = NULL; sr_change_oper_t oper; - sr_val_t *old_val = NULL; - sr_val_t *new_val = NULL; - char *tmp = NULL; - char static_prefix[XPATH_SIZE] = {0}; - char next_hop_index[XPATH_SIZE] = {0}; - char interface[XPATH_SIZE] = {0}; - char old_interface[XPATH_SIZE] = {0}; + sr_val_t *old, *new, *tmp; + sr_xpath_ctx_t state = {0}; + bool interface_set = false; int rc = SR_ERR_OK; + UNUSED(private_ctx); - // if we receive event SR_EV_APPLY - config has changed - - log_recv_event(event, "subtree_change_cb received"); - SRP_LOG_DBG("[SRP_LOG_DBG] xpath: %s", xpath); + SRP_LOG_INF("In %s", __FUNCTION__); - if (event != SR_EV_APPLY) { + if (event == SR_EV_APPLY) return SR_ERR_OK; - } - if (sr_get_changes_iter(ds, (char *)xpath, &it) != SR_ERR_OK) { - // in example he calls even on fale + rc = sr_get_changes_iter(ds, (char *)xpath, &it); + if (rc != SR_ERR_OK) { sr_free_change_iter(it); - return SR_ERR_OK; + return rc; } - while (sr_get_change_next(ds, it, &oper, - &old_val, &new_val) == SR_ERR_OK) { + foreach_change(ds, it, oper, old, new) { - log_recv_oper(oper, "subtree_change_cb received"); + SRP_LOG_DBG("xpath: %s", new->xpath); - SRP_LOG_DBG("xpath: %s", new_val->xpath); + rc = get_xpath_key(prefix, new->xpath, "static", "prefix", + VPP_IP4_PREFIX_STRING_LEN, &state); - sr_xpath_ctx_t state = {0}; - - tmp = xpath_find_first_key(new_val->xpath, "prefix", &state); - if (NULL == tmp) { - SRP_LOG_DBG_MSG("static_prefix NOT found."); - continue; - } - - strncpy(static_prefix, tmp, XPATH_SIZE); - sr_xpath_recover(&state); - - tmp = xpath_find_first_key(new_val->xpath, "index", &state); - if (NULL == tmp) { - SRP_LOG_DBG_MSG("next-hop_index NOT found."); - continue; - } - - strncpy(next_hop_index, tmp, XPATH_SIZE); - sr_xpath_recover(&state); + rc |= get_xpath_key(index, new->xpath, "next-hop", "index", + HOP_INDEX_SIZE, &state); + if (rc) + goto error; switch (oper) { - case SR_OP_CREATED: - if (sr_xpath_node_name_eq(new_val->xpath, "interface")) { - strncpy(interface, new_val->data.string_val, XPATH_SIZE); - rc = set_route(ds, next_hop_index, interface, NULL, - static_prefix, true); - } else if (sr_xpath_node_name_eq(new_val->xpath, - "subinterface")) { - } - break; - case SR_OP_MODIFIED: - if (sr_xpath_node_name_eq(old_val->xpath, "interface")) { - strncpy(old_interface, old_val->data.string_val, - XPATH_SIZE); - rc = set_route(ds, next_hop_index, old_interface, NULL, - static_prefix, false); - } else if (sr_xpath_node_name_eq(old_val->xpath, - "subinterface")) { - } - - if (sr_xpath_node_name_eq(new_val->xpath, "interface")) { - strncpy(interface, new_val->data.string_val, XPATH_SIZE); - rc = set_route(ds, next_hop_index, interface, NULL, - static_prefix, true); - } else if (sr_xpath_node_name_eq(new_val->xpath, - "subinterface")) { - } - break; - - case SR_OP_MOVED: + case SR_OP_CREATED: + tmp = new; break; - case SR_OP_DELETED: - if (sr_xpath_node_name_eq(old_val->xpath, "interface")) { - strncpy(old_interface, old_val->data.string_val, - XPATH_SIZE); - rc = set_route(ds, next_hop_index, old_interface, NULL, - static_prefix, false); - } else if (sr_xpath_node_name_eq(old_val->xpath, - "subinterface")) { - } + tmp = old; + break; + default: + SRP_LOG_WRN_MSG("Operation not supported"); break; } - if (SR_ERR_OK != rc) { - sr_xpath_recover(&state); + if (sr_xpath_node_name_eq(tmp->xpath, "config")) { + SRP_LOG_DBG("xpath: %s", tmp->xpath); + } else if (sr_xpath_node_name_eq(tmp->xpath, "interface")) { + strncpy(interface, tmp->data.string_val, VPP_INTFC_NAME_LEN); + interface_set = true; + } else { //metric, recurse + SRP_LOG_ERR("Unsupported field %s", tmp->xpath); + return SR_ERR_UNSUPPORTED; + } - sr_free_val(old_val); - sr_free_val(new_val); + if (oper == SR_OP_CREATED && interface_set) { + rc = set_route(ds, index, interface, NULL, prefix, true); + interface_set = false; + } else if (oper == SR_OP_MODIFIED && interface_set) { + rc = set_route(ds, index, interface, NULL, prefix, false); + rc |= set_route(ds, index, interface, NULL, prefix, true); + interface_set = false; + } else if (oper == SR_OP_DELETED && interface_set) { + rc = set_route(ds, index, interface, NULL, prefix, false); + interface_set = false; + } - sr_free_change_iter(it); - return SR_ERR_OPERATION_FAILED; + if (rc != 0) { + SRP_LOG_ERR_MSG("setting route failed"); + goto error; } + sr_free_val(old); + sr_free_val(new); sr_xpath_recover(&state); - - sr_free_val(old_val); - sr_free_val(new_val); } sr_free_change_iter(it); return SR_ERR_OK; -} - -typedef struct -{ - u8 length; - u8 address[4]; -} address_prefix_t; - -typedef struct { - char *next_hop_index; - address_prefix_t address_prefix; - const bool is_interface_ref; - sw_interface_details_query_t sw_interface_details_query; - sysr_values_ctx_t sysr_values_ctx; -} sysr_ip_fib_details_ctx_t; - -static -bool address_prefix_cmp(address_prefix_t* address_prefix, - vapi_payload_ip_fib_details* reply) -{ - ARG_CHECK2(false, address_prefix, reply); - - if (address_prefix->length == reply->address_length) - { - if (0 == memcmp(address_prefix->address, reply->address, sizeof(reply->address))) - return true; - } - - return false; -} - -static -bool address_prefix_init(address_prefix_t* address_prefix, char* str_prefix) -{ - ARG_CHECK2(false, address_prefix, str_prefix); - - address_prefix->length = ip_prefix_split(str_prefix); - if(address_prefix->length < 1) - { - SRP_LOG_ERR_MSG("not a valid prefix"); - return false; - } - return sc_aton(str_prefix, address_prefix->address, - sizeof(address_prefix->address)); +error: + sr_free_val(old); + sr_free_val(new); + sr_xpath_recover(&state); + sr_free_change_iter(it); + return rc; } // XPATH: /openconfig-local-routing:local-routes/static-routes/static/state -int openconfig_local_routing_local_routes_static_routes_static_state_vapi_cb( - vapi_payload_ip_fib_details *reply, - sysr_ip_fib_details_ctx_t *sysr_ip_fib_details_ctx) +static int oc_prefix_state_cb( + const char *xpath, sr_val_t **values, size_t *values_cnt, + uint64_t request_id, const char *original_xpath, void *private_ctx) { + UNUSED(request_id); UNUSED(original_xpath); UNUSED(private_ctx); + char prefix[VPP_IP4_PREFIX_STRING_LEN] = {0}; + sr_xpath_ctx_t state = {0}; sr_val_t *vals = NULL; + fib_dump_t *reply = NULL; + int vc = 1; int rc = 0; - int vc = 0; - char address_prefix[INET_ADDRSTRLEN + 3] = {0}; - vc = 1; - ARG_CHECK2(SR_ERR_INVAL_ARG, reply, sysr_ip_fib_details_ctx); + ARG_CHECK3(SR_ERR_INVAL_ARG, xpath, values, values_cnt); - rc = sr_new_values(vc, &vals); - if (SR_ERR_OK != rc) { - return rc; - } + SRP_LOG_INF("In %s", __FUNCTION__); - //Filling the structure - snprintf(address_prefix, sizeof(address_prefix), "%s/%u", - sc_ntoa(reply->address), reply->address_length); + rc = get_xpath_key(prefix, (char *)xpath, "static", "prefix", + VPP_IP4_PREFIX_STRING_LEN, &state); + if (rc != 0) + return SR_ERR_INVAL_ARG; - sr_val_build_xpath(&vals[0], "%s/prefix", - sysr_ip_fib_details_ctx->sysr_values_ctx.xpath_root); - sr_val_set_str_data(&vals[0], SR_STRING_T, address_prefix); + rc = ipv4_fib_dump_prefix(prefix, &reply); + if (rc == -SCVPP_NOT_FOUND) { + SRP_LOG_ERR("Prefix %s not found in VPP FIB", prefix); + return SR_ERR_NOT_FOUND; + } - sysr_ip_fib_details_ctx->sysr_values_ctx.values = vals; - sysr_ip_fib_details_ctx->sysr_values_ctx.values_cnt = vc; + /* Allocation for number of elements dumped by ipv4_fib_dump_all */ + rc = sr_new_values(vc, &vals); + if (SR_ERR_OK != rc) + return rc; - return SR_ERR_OK; -} + sr_val_build_xpath(&vals[0], "%s/prefix", xpath); + sr_val_set_str_data(&vals[0], SR_STRING_T, prefix); -vapi_error_e -ip_routing_dump_cb (struct vapi_ctx_s *ctx, void *callback_ctx, - vapi_error_e rv, bool is_last, - vapi_payload_ip_fib_details * reply) -{ - if (is_last) - { - assert (NULL == reply); - } - else - { - sysr_ip_fib_details_ctx_t *dctx = callback_ctx; - assert(dctx && reply); + sr_xpath_recover(&state); - if (address_prefix_cmp(&dctx->address_prefix, reply)) - { - openconfig_local_routing_local_routes_static_routes_static_state_vapi_cb(reply, - dctx); - } - } + free(reply); + *values = vals; + *values_cnt = vc; - return VAPI_OK; + return SR_ERR_OK; } -int openconfig_local_routing_local_routes_static_routes_static_state_cb( - const char *xpath, sr_val_t **values, size_t *values_cnt, - __attribute__((unused)) uint64_t request_id, - __attribute__((unused)) const char *original_xpath, - __attribute__((unused)) void *private_ctx) +// XPATH /openconfig-local-routing:local-routes/static-routes/static/next-hops/next-hop/state +static int +oc_next_hop_state_cb(const char *xpath, sr_val_t **values, size_t *values_cnt, + uint64_t request_id, const char *original_xpath, + void *private_ctx) { + UNUSED(request_id); UNUSED(original_xpath); UNUSED(private_ctx); + char prefix[VPP_IP4_PREFIX_STRING_LEN] = {0}; + char index[HOP_INDEX_SIZE]; + char next_hop[INET_ADDRSTRLEN] = {0}; + fib_dump_t *reply = NULL; sr_xpath_ctx_t state = {0}; - vapi_error_e rv = 0; - char *tmp = NULL; - char static_prefix[XPATH_SIZE] = {0}; - sysr_ip_fib_details_ctx_t dctx = {0}; + sr_val_t *vals = NULL; + int vc = 3; + int rc = 0; ARG_CHECK3(SR_ERR_INVAL_ARG, xpath, values, values_cnt); - tmp = xpath_find_first_key(xpath, "prefix", &state); - if (NULL == tmp) { - SRP_LOG_ERR_MSG("static_prefix not found."); - return SR_ERR_INVAL_ARG; - } + SRP_LOG_INF("In %s", __FUNCTION__); - strncpy(static_prefix, tmp, XPATH_SIZE); - sr_xpath_recover(&state); + /* Get prefix and index key from XPATH */ + rc = get_xpath_key(prefix, (char *)xpath, "static", "prefix", + VPP_IP4_PREFIX_STRING_LEN, &state); - //VPP callback - snprintf(dctx.sysr_values_ctx.xpath_root, XPATH_SIZE, "/openconfig-local-routing:local-routes/static-routes/static[prefix='%s']/state", static_prefix); + rc |= get_xpath_key(index, (char*)xpath, "next-hop", "index", + VPP_IP4_PREFIX_STRING_LEN, &state); - if (!address_prefix_init(&dctx.address_prefix, static_prefix)) - { + if (rc != 0) return SR_ERR_INVAL_ARG; - } - - vapi_msg_ip_fib_dump *mp = vapi_alloc_ip_fib_dump (g_vapi_ctx_instance); - - VAPI_CALL(vapi_ip_fib_dump(g_vapi_ctx_instance, mp, ip_routing_dump_cb, &dctx)); - if(VAPI_OK != rv) - { - SRP_LOG_ERR_MSG("VAPI call failed"); + rc = ipv4_fib_dump_prefix(prefix, &reply); + if (rc != SCVPP_OK) { + SRP_LOG_ERR("Fail to dump prefix %s", prefix); return SR_ERR_INVAL_ARG; } - sr_xpath_recover(&state); - *values = dctx.sysr_values_ctx.values; - *values_cnt = dctx.sysr_values_ctx.values_cnt; - - return SR_ERR_OK; -} - -// // XPATH: /openconfig-local-routing:local-routes/static-routes/l/next-hops/next-hop/state -int openconfig_local_routing_local_routes_static_routes_static_next_hops_next_hop_state_vapi_cb( - vapi_type_fib_path *reply, - sysr_ip_fib_details_ctx_t *sysr_ip_fib_details_ctx) -{ - sr_val_t *vals = NULL; - int rc = 0; - int vc = 0; - char next_hop[INET_ADDRSTRLEN] = {0}; - - ARG_CHECK2(SR_ERR_INVAL_ARG, reply, sysr_ip_fib_details_ctx); - - vc = 3; - /* convenient functions such as this can be found in sysrepo/values.h */ rc = sr_new_values(vc, &vals); - if (SR_ERR_OK != rc) { + if (SR_ERR_OK != rc) return rc; + + // check next hop index equals next hop id + if (strtoul(index, NULL, 0) != reply->path[0].next_hop_id) { + SRP_LOG_ERR("next hop index is %d for prefix %s", + reply->path[0].next_hop_id, prefix); + SRP_LOG_ERR("before %s, stroul is %d", index, strtoul(index, NULL, 0)); + return SR_ERR_INVAL_ARG; } - sr_val_build_xpath(&vals[0], "%s/index", - sysr_ip_fib_details_ctx->sysr_values_ctx.xpath_root); - sr_val_set_str_data(&vals[0], SR_STRING_T, - sysr_ip_fib_details_ctx->next_hop_index); + sr_val_build_xpath(&vals[0], "%s/index", xpath); + sr_val_set_str_data(&vals[0], SR_STRING_T, index); - strncpy(next_hop, sc_ntoa(reply->next_hop), sizeof(next_hop)); - sr_val_build_xpath(&vals[1], "%s/next-hop", sysr_ip_fib_details_ctx->sysr_values_ctx.xpath_root); - sr_val_set_str_data(&vals[1], SR_STRING_T, next_hop); + strncpy(next_hop, sc_ntoa(reply->path[0].next_hop), VPP_IP4_ADDRESS_LEN); + sr_val_build_xpath(&vals[1], "%s/next-hop", xpath); + sr_val_set_str_data(&vals[1], SR_STRING_T, (char *)reply->path[0].next_hop); - sr_val_build_xpath(&vals[2], "%s/metric", sysr_ip_fib_details_ctx->sysr_values_ctx.xpath_root); + sr_val_build_xpath(&vals[2], "%s/metric", xpath); vals[2].type = SR_UINT32_T; - vals[2].data.uint32_val = reply->weight; - - // sr_val_build_xpath(&vals[3], "%s/recurse", sysr_ip_fib_details_ctx->sysr_values_ctx.xpath_root); - // vals[3].type = SR_BOOL_T; - // vals[3].data.bool_val = YANG INPUT TYPE: boolean; + vals[2].data.uint32_val = reply->path[0].weight; - sysr_ip_fib_details_ctx->sysr_values_ctx.values = vals; - sysr_ip_fib_details_ctx->sysr_values_ctx.values_cnt = vc; + free(reply); + sr_xpath_recover(&state); + *values = vals; + *values_cnt = vc; return SR_ERR_OK; } -// // XPATH: /openconfig-local-routing:local-routes/static-routes/l/next-hops/next-hop/interface-ref/state -int openconfig_local_routing_local_routes_static_routes_static_next_hops_next_hop_interface_ref_state_vapi_cb( - sysr_ip_fib_details_ctx_t * dctx) +// XPATH /openconfig-local-routing:local-routes/static-routes/static/next-hops/next-hop/interface-ref/state +static int +oc_next_hop_interface_state_cb(const char *xpath, sr_val_t **values, + size_t *values_cnt, uint64_t request_id, + const char *original_xpath, void *private_ctx) { + UNUSED(request_id); UNUSED(original_xpath); UNUSED(private_ctx); + sr_xpath_ctx_t state = {0}; + char prefix[VPP_IP4_PREFIX_STRING_LEN] = {0}; + char interface[VPP_INTFC_NAME_LEN] = {0}; + char index[HOP_INDEX_SIZE]; //next hop index + fib_dump_t *reply = NULL; sr_val_t *vals = NULL; + int vc = 1; int rc = 0; - int vc = 0; - - ARG_CHECK(SR_ERR_INVAL_ARG, dctx); - - vc = 2; - /* convenient functions such as this can be found in sysrepo/values.h */ - rc = sr_new_values(vc, &vals); - if (SR_ERR_OK != rc) { - return rc; - } - sr_val_build_xpath(&vals[0], "%s/interface", - dctx->sysr_values_ctx.xpath_root); - sr_val_set_str_data(&vals[0], SR_STRING_T, - (const char*)dctx->sw_interface_details_query.sw_interface_details.interface_name); + //ARG_CHECK3(SR_ERR_INVAL_ARG, xpath, values, values_cnt); - sr_val_build_xpath(&vals[1], "%s/subinterface", - dctx->sysr_values_ctx.xpath_root); - vals[1].type = SR_UINT32_T; - vals[1].data.uint32_val = 0; + SRP_LOG_INF("In %s", __FUNCTION__); - dctx->sysr_values_ctx.values = vals; - dctx->sysr_values_ctx.values_cnt = vc; + ///* Get prefix key from XPATH */ + rc = get_xpath_key(prefix, (char*) xpath, "static", "prefix", + VPP_IP4_PREFIX_STRING_LEN, &state); - return SR_ERR_OK; -} - -vapi_error_e -ip_routing_next_hop_dump_cb (struct vapi_ctx_s *ctx, void *callback_ctx, - vapi_error_e rv, bool is_last, - vapi_payload_ip_fib_details * reply) -{ - ARG_CHECK(VAPI_EINVAL, callback_ctx); - - sysr_ip_fib_details_ctx_t *dctx = callback_ctx; - - if (is_last) - { - assert (NULL == reply); - } - else - { - assert (NULL != reply); - - if (reply->count > 0 && address_prefix_cmp(&dctx->address_prefix, reply)) - { - if (dctx->is_interface_ref) - { - dctx->sw_interface_details_query.interface_found = true; - dctx->sw_interface_details_query.sw_interface_details.sw_if_index = reply->path[0].sw_if_index; - //sw_interface_dump will have to be called outside this VAPI - } - else - { - openconfig_local_routing_local_routes_static_routes_static_next_hops_next_hop_state_vapi_cb(reply->path, dctx); - } - } - } - - return VAPI_OK; -} - -int next_hop_inner( - bool is_interface_ref, const char *xpath, sr_val_t **values, - size_t *values_cnt, __attribute__((unused)) uint64_t request_id, - __attribute__((unused)) void *private_ctx) -{ - sr_xpath_ctx_t state = {0}; - vapi_error_e rv; - char *tmp = NULL; - char static_prefix[XPATH_SIZE] = {0}; - char next_hop_index[XPATH_SIZE] = {0}; - sysr_ip_fib_details_ctx_t dctx = {.is_interface_ref = is_interface_ref}; - - ARG_CHECK3(SR_ERR_INVAL_ARG, xpath, values, values_cnt); + rc |= get_xpath_key(index, (char *)xpath, "next-hop", "index", + HOP_INDEX_SIZE, &state); - tmp = xpath_find_first_key(xpath, "prefix", &state); - if (NULL == tmp) { - SRP_LOG_ERR_MSG("static_prefix not found."); + if (rc != 0) return SR_ERR_INVAL_ARG; - } - strncpy(static_prefix, tmp, XPATH_SIZE); - sr_xpath_recover(&state); - tmp = xpath_find_first_key(xpath, "index", &state); - if (NULL == tmp) { - SRP_LOG_ERR_MSG("index not found."); + rc = ipv4_fib_dump_prefix(prefix, &reply); + if (rc != SCVPP_OK) { + SRP_LOG_ERR("Fail to dump prefix %s", prefix); return SR_ERR_INVAL_ARG; } - strncpy(next_hop_index, tmp, XPATH_SIZE); - sr_xpath_recover(&state); + //TODO: check nhop? - //VPP callback - dctx.next_hop_index = next_hop_index; - if (is_interface_ref) { - snprintf(dctx.sysr_values_ctx.xpath_root, XPATH_SIZE, - "/openconfig-local-routing:local-routes/static-routes/static[prefix='%s']/next-hops/next-hop[index='%s']/interface-ref/state", - static_prefix, next_hop_index); - } else { - snprintf(dctx.sysr_values_ctx.xpath_root, XPATH_SIZE, - "/openconfig-local-routing:local-routes/static-routes/static[prefix='%s']/next-hops/next-hop[index='%s']/state", - static_prefix, next_hop_index); - } + rc = sr_new_values(vc, &vals); + if (SR_ERR_OK != rc) + return rc; - if (!address_prefix_init(&dctx.address_prefix, static_prefix)) - { + // check next hop index equals next hop id + if (strtoul(index, NULL, 0) != reply->path[0].next_hop_id) { + SRP_LOG_ERR("next hop index is %d for prefix %s", + reply->path[0].next_hop_id, prefix); + SRP_LOG_ERR("before %s, stroul is %d", index, strtoul(index, NULL, 0)); return SR_ERR_INVAL_ARG; } - vapi_msg_ip_fib_dump *mp = vapi_alloc_ip_fib_dump (g_vapi_ctx_instance); - VAPI_CALL(vapi_ip_fib_dump(g_vapi_ctx_instance, mp, ip_routing_next_hop_dump_cb, &dctx)); - if (VAPI_OK != rv) - { - SRP_LOG_ERR_MSG("VAPI call failed"); + rc = get_interface_name(interface, reply->path[0].sw_if_index); + if (rc != SCVPP_OK) { + SRP_LOG_ERR("No interface name for id %d", reply->path[0].sw_if_index); return SR_ERR_INVAL_ARG; } - if (is_interface_ref) - { - if (dctx.sw_interface_details_query.interface_found) - { - if (!get_interface_name(&dctx.sw_interface_details_query)) - { - return SR_ERR_INVAL_ARG; - } - if (strlen((const char*) - dctx.sw_interface_details_query.sw_interface_details.interface_name)) { - openconfig_local_routing_local_routes_static_routes_static_next_hops_next_hop_interface_ref_state_vapi_cb(&dctx); - } - } - } + sr_val_build_xpath(&vals[0], "%s/interface", xpath); + sr_val_set_str_data(&vals[0], SR_STRING_T, interface); + free(reply); sr_xpath_recover(&state); - *values = dctx.sysr_values_ctx.values; - *values_cnt = dctx.sysr_values_ctx.values_cnt; + *values = vals; + *values_cnt = vc; return SR_ERR_OK; } -int openconfig_local_routing_local_routes_static_routes_static_next_hops_next_hop_state_cb( - const char *xpath, sr_val_t **values, size_t *values_cnt, - uint64_t request_id, const char *original_xpath, void *private_ctx) -{ - return next_hop_inner(false, xpath, values, values_cnt, request_id, - private_ctx); -} - -int openconfig_local_routing_local_routes_static_routes_static_next_hops_next_hop_interface_ref_state_cb( - const char *xpath, sr_val_t **values, size_t *values_cnt, - uint64_t request_id, const char *original_xpath, void *private_ctx) -{ - return next_hop_inner(true, xpath, values, values_cnt, request_id, - private_ctx); -} - const xpath_t oc_local_routing_xpaths[OC_LROUTING_SIZE] = { { - .xpath = "openconfig-local-routing", - .method = MODULE, + .xpath = "/openconfig-local-routing:local-routes/static-routes/static/config", + .method = XPATH, .datastore = SR_DS_RUNNING, - .cb.mcb = openconfig_local_routing_mod_cb, + .cb.scb = oc_prefix_config_cb, .private_ctx = NULL, .priority = 0, - //.opts = SR_SUBSCR_EV_ENABLED | SR_SUBSCR_APPLY_ONLY - .opts = SR_SUBSCR_EV_ENABLED | SR_SUBSCR_APPLY_ONLY | SR_SUBSCR_CTX_REUSE + //.opts = SR_SUBSCR_DEFAULT + .opts = SR_SUBSCR_CTX_REUSE }, { .xpath = "/openconfig-local-routing:local-routes/static-routes/static/next-hops/next-hop/config", .method = XPATH, .datastore = SR_DS_RUNNING, - .cb.scb = openconfig_local_routing_local_routes_static_routes_static_next_hops_next_hop_config_cb, + .cb.scb = oc_next_hop_config_cb, .private_ctx = NULL, .priority = 0, //.opts = SR_SUBSCR_DEFAULT @@ -752,7 +514,7 @@ const xpath_t oc_local_routing_xpaths[OC_LROUTING_SIZE] = { .xpath = "/openconfig-local-routing:local-routes/static-routes/static/next-hops/next-hop/interface-ref/config", .method = XPATH, .datastore = SR_DS_RUNNING, - .cb.scb = openconfig_local_routing_local_routes_static_routes_static_next_hops_next_hop_interface_ref_config_cb, + .cb.scb = oc_next_hop_interface_config_cb, .private_ctx = NULL, .priority = 0, //.opts = SR_SUBSCR_DEFAULT @@ -762,7 +524,7 @@ const xpath_t oc_local_routing_xpaths[OC_LROUTING_SIZE] = { .xpath = "/openconfig-local-routing:local-routes/static-routes/static/state", .method = GETITEM, .datastore = SR_DS_RUNNING, - .cb.gcb = openconfig_local_routing_local_routes_static_routes_static_state_cb, + .cb.gcb = oc_prefix_state_cb, .private_ctx = NULL, .priority = 0, .opts = SR_SUBSCR_CTX_REUSE @@ -771,7 +533,7 @@ const xpath_t oc_local_routing_xpaths[OC_LROUTING_SIZE] = { .xpath = "/openconfig-local-routing:local-routes/static-routes/static/next-hops/next-hop/state", .method = GETITEM, .datastore = SR_DS_RUNNING, - .cb.gcb = openconfig_local_routing_local_routes_static_routes_static_next_hops_next_hop_state_cb, + .cb.gcb = oc_next_hop_state_cb, .private_ctx = NULL, .priority = 0, .opts = SR_SUBSCR_CTX_REUSE @@ -780,7 +542,7 @@ const xpath_t oc_local_routing_xpaths[OC_LROUTING_SIZE] = { .xpath = "/openconfig-local-routing:local-routes/static-routes/static/next-hops/next-hop/interface-ref/state", .method = GETITEM, .datastore = SR_DS_RUNNING, - .cb.gcb = openconfig_local_routing_local_routes_static_routes_static_next_hops_next_hop_interface_ref_state_cb, + .cb.gcb = oc_next_hop_interface_state_cb, .private_ctx = NULL, .priority = 0, .opts = SR_SUBSCR_CTX_REUSE diff --git a/src/plugins/openconfig/openconfig_local_routing.h b/src/plugins/openconfig/openconfig_local_routing.h deleted file mode 100644 index 13d2982..0000000 --- a/src/plugins/openconfig/openconfig_local_routing.h +++ /dev/null @@ -1,25 +0,0 @@ -/* - * Copyright (c) 2018 PANTHEON.tech. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at: - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef __OPENCONFIG_LOCAL_ROUTING_H__ -#define __OPENCONFIG_LOCAL_ROUTING_H__ - -#include "../sc_model.h" - -#define OC_LROUTING_SIZE 6 -extern const xpath_t oc_local_routing_xpaths[OC_LROUTING_SIZE]; - -#endif /* __OPENCONFIG_LOCAL_ROUTING_H__ */ |