diff --git a/src/interfaces/src/plugin/api/interfaces/interface/ipv4/address/change.c b/src/interfaces/src/plugin/api/interfaces/interface/ipv4/address/change.c index f58b2e8a..6d570337 100644 --- a/src/interfaces/src/plugin/api/interfaces/interface/ipv4/address/change.c +++ b/src/interfaces/src/plugin/api/interfaces/interface/ipv4/address/change.c @@ -307,23 +307,23 @@ int interfaces_interface_ipv4_address_change_ip(void* priv, sr_session_ctx_t* se SRPC_SAFE_CALL_ERR_COND(error, error < 0, snprintf(path_buffer, sizeof(path_buffer), "%s[name=\"%s\"]/ietf-ip:ipv4/address[ip=\"%s\"]/prefix-length", INTERFACES_INTERFACES_LIST_YANG_PATH, interface_name_buffer, node_value), error_out); SRPC_SAFE_CALL_ERR(error, srpc_iterate_changes(ctx, session, path_buffer, interfaces_interface_ipv4_address_get_prefix_length, NULL, NULL), error_out); - if (!mod_ctx->mod_data.prefix_set) { + if (!mod_ctx->mod_data.ipv4.address.prefix_set) { // prefix not found - check for netmask SRPC_SAFE_CALL_ERR_COND(error, error < 0, snprintf(path_buffer, sizeof(path_buffer), "%s[name=\"%s\"]/ietf-ip:ipv4/address[ip=\"%s\"]/netmask", INTERFACES_INTERFACES_LIST_YANG_PATH, interface_name_buffer, node_value), error_out); SRPC_SAFE_CALL_ERR(error, srpc_iterate_changes(ctx, session, path_buffer, interfaces_interface_ipv4_address_get_netmask, NULL, NULL), error_out); - if (!mod_ctx->mod_data.prefix_set) { + if (!mod_ctx->mod_data.ipv4.address.prefix_set) { SRPLG_LOG_ERR(PLUGIN_NAME, "Unable to get prefix-length/netmask for address %s... Discarding changes", node_value); goto error_out; } } - SRPLG_LOG_INF(PLUGIN_NAME, "Recieved prefix-length of %d for address %s", mod_ctx->mod_data.prefix_length, node_value); + SRPLG_LOG_INF(PLUGIN_NAME, "Recieved prefix-length of %d for address %s", mod_ctx->mod_data.ipv4.address.prefix_length, node_value); // prefix was set and found // set final prefix length - nl_addr_set_prefixlen(local_addr, mod_ctx->mod_data.prefix_length); + nl_addr_set_prefixlen(local_addr, mod_ctx->mod_data.ipv4.address.prefix_length); // set to route address SRPC_SAFE_CALL_ERR(error, rtnl_addr_set_local(request_addr, local_addr), error_out); @@ -404,8 +404,8 @@ int interfaces_interface_ipv4_address_change_ip(void* priv, sr_session_ctx_t* se } // re-initialize mod_ctx data - mod_ctx->mod_data.prefix_length = 0; - mod_ctx->mod_data.prefix_set = false; + mod_ctx->mod_data.ipv4.address.prefix_length = 0; + mod_ctx->mod_data.ipv4.address.prefix_set = false; return error; } @@ -431,8 +431,8 @@ static int interfaces_interface_ipv4_address_get_prefix_length(void* priv, sr_se assert(change_ctx->operation == SR_OP_CREATED); // parse prefix length - mod_ctx->mod_data.prefix_length = (uint8_t)atoi(node_value); - mod_ctx->mod_data.prefix_set = true; + mod_ctx->mod_data.ipv4.address.prefix_length = (uint8_t)atoi(node_value); + mod_ctx->mod_data.ipv4.address.prefix_set = true; return error; } @@ -459,13 +459,14 @@ static int interfaces_interface_ipv4_address_get_netmask(void* priv, sr_session_ SRPC_SAFE_CALL_ERR(error, interfaces_interface_ipv4_address_netmask2prefix(node_value, &prefix_length), error_out); // set mod changes prefix length - mod_ctx->mod_data.prefix_length = prefix_length; - mod_ctx->mod_data.prefix_set = true; + mod_ctx->mod_data.ipv4.address.prefix_length = prefix_length; + mod_ctx->mod_data.ipv4.address.prefix_set = true; goto out; error_out: error = -1; + mod_ctx->mod_data.ipv4.address.prefix_set = false; out: return error; diff --git a/src/interfaces/src/plugin/api/interfaces/interface/ipv4/change.c b/src/interfaces/src/plugin/api/interfaces/interface/ipv4/change.c index 9469376f..0b322347 100644 --- a/src/interfaces/src/plugin/api/interfaces/interface/ipv4/change.c +++ b/src/interfaces/src/plugin/api/interfaces/interface/ipv4/change.c @@ -36,7 +36,7 @@ int interfaces_interface_ipv4_change_neighbor(void* priv, sr_session_ctx_t* sess break; } - return -1; + return error; } void interfaces_interface_ipv4_change_neighbor_free(void* priv) diff --git a/src/interfaces/src/plugin/api/interfaces/interface/ipv4/neighbor/change.c b/src/interfaces/src/plugin/api/interfaces/interface/ipv4/neighbor/change.c index 047ac005..067c5f98 100644 --- a/src/interfaces/src/plugin/api/interfaces/interface/ipv4/neighbor/change.c +++ b/src/interfaces/src/plugin/api/interfaces/interface/ipv4/neighbor/change.c @@ -1,8 +1,17 @@ #include "change.h" +#include "netlink/addr.h" #include "plugin/common.h" +#include "plugin/context.h" +#include #include +#include +#include +#include + +static int interfaces_interface_ipv4_address_get_link_layer_address(void* priv, sr_session_ctx_t* session, const srpc_change_ctx_t* change_ctx); + int interfaces_interface_ipv4_neighbor_change_link_layer_address_init(void* priv) { int error = 0; @@ -44,25 +53,161 @@ int interfaces_interface_ipv4_neighbor_change_ip_init(void* priv) int interfaces_interface_ipv4_neighbor_change_ip(void* priv, sr_session_ctx_t* session, const srpc_change_ctx_t* change_ctx) { int error = 0; + void* error_ptr = NULL; + + // sysrepo + // sr_val_t* link_layer_address_val = NULL; + sr_conn_ctx_t* conn_ctx = NULL; + sr_session_ctx_t* running_session = NULL; + + // strings and buffers const char* node_name = LYD_NAME(change_ctx->node); const char* node_value = lyd_get_value(change_ctx->node); + char path_buffer[PATH_MAX] = { 0 }; + char interface_name_buffer[100] = { 0 }; + // char address_buffer[100] = { 0 }; + + // app context + interfaces_ctx_t* ctx = priv; + + // mod changes context + interfaces_mod_changes_ctx_t* mod_ctx = &ctx->mod_ctx; + + // libnl + struct rtnl_neigh* request_neigh = NULL; + struct rtnl_link* current_link = NULL; + struct nl_addr* dst_addr = NULL; + struct nl_addr* ll_addr = NULL; SRPLG_LOG_INF(PLUGIN_NAME, "Node Name: %s; Previous Value: %s, Value: %s; Operation: %d", node_name, change_ctx->previous_value, node_value, change_ctx->operation); + // get node path + SRPC_SAFE_CALL_PTR(error_ptr, lyd_path(change_ctx->node, LYD_PATH_STD, path_buffer, sizeof(path_buffer)), error_out); + + // get interface name + SRPC_SAFE_CALL_ERR(error, srpc_extract_xpath_key_value(path_buffer, "interface", "name", interface_name_buffer, sizeof(interface_name_buffer)), error_out); + + SRPLG_LOG_INF(PLUGIN_NAME, "Node Path: %s; Interface Name: %s", path_buffer, interface_name_buffer); + + // get link + SRPC_SAFE_CALL_PTR(current_link, rtnl_link_get_by_name(mod_ctx->nl_ctx.link_cache, interface_name_buffer), error_out); + + // get connection + SRPC_SAFE_CALL_PTR(conn_ctx, sr_session_get_connection(session), error_out); + + // start a running DS session - fetching data about prefix when deleting the address + SRPC_SAFE_CALL_ERR(error, sr_session_start(conn_ctx, SR_DS_RUNNING, &running_session), error_out); + switch (change_ctx->operation) { case SR_OP_CREATED: + // new neighbor + request_neigh = rtnl_neigh_alloc(); + + // parse destination address + SRPC_SAFE_CALL_ERR(error, nl_addr_parse(node_value, AF_INET, &dst_addr), error_out); + + // get prefix length by using prefix-length or netmask leafs + SRPC_SAFE_CALL_ERR_COND(error, error < 0, snprintf(path_buffer, sizeof(path_buffer), INTERFACES_INTERFACES_INTERFACE_YANG_PATH "[name=\"%s\"]/ietf-ip:ipv4/neighbor[ip=\"%s\"]/link-layer-address", interface_name_buffer, node_value), error_out); + SRPC_SAFE_CALL_ERR(error, srpc_iterate_changes(ctx, session, path_buffer, interfaces_interface_ipv4_address_get_link_layer_address, NULL, NULL), error_out); + + SRPLG_LOG_INF(PLUGIN_NAME, "Recieved link-layer-address %s for neighbor address %s", mod_ctx->mod_data.ipv4.neighbor.link_layer_address, node_value); + + // parse link-layer address + SRPC_SAFE_CALL_ERR(error, nl_addr_parse(mod_ctx->mod_data.ipv4.neighbor.link_layer_address, AF_LLC, &ll_addr), error_out); + + // set addresses to the new neighbor + SRPC_SAFE_CALL_ERR(error, rtnl_neigh_set_dst(request_neigh, dst_addr), error_out); + rtnl_neigh_set_lladdr(request_neigh, ll_addr); + + // set interface + rtnl_neigh_set_ifindex(request_neigh, rtnl_link_get_ifindex(current_link)); + + // add neighbor + SRPC_SAFE_CALL_ERR(error, rtnl_neigh_add(mod_ctx->nl_ctx.socket, request_neigh, NLM_F_CREATE), error_out); + break; case SR_OP_MODIFIED: + // should be impossible - address IP can only be created and deleted + SRPLG_LOG_ERR(PLUGIN_NAME, "Unsuported operation MODIFY for interface IPv4 neighbor IP leaf"); + goto error_out; break; case SR_OP_DELETED: + request_neigh = rtnl_neigh_alloc(); + + // set interface + rtnl_neigh_set_ifindex(request_neigh, rtnl_link_get_ifindex(current_link)); + + // parse destination + SRPC_SAFE_CALL_ERR(error, nl_addr_parse(node_value, AF_INET, &dst_addr), error_out); + + // set destination + SRPC_SAFE_CALL_ERR(error, rtnl_neigh_set_dst(request_neigh, dst_addr), error_out); + + // remove wanted neighbor + SRPC_SAFE_CALL_ERR(error, rtnl_neigh_delete(mod_ctx->nl_ctx.socket, request_neigh, 0), error_out); + break; case SR_OP_MOVED: break; } + goto out; + +error_out: + if (error < 0) { + SRPLG_LOG_INF(PLUGIN_NAME, "nl_geterror(): %s", nl_geterror(error)); + } + error = -1; + +out: + if (running_session) { + sr_session_stop(running_session); + } + + // re-initialize mod_ctx data + if (mod_ctx->mod_data.ipv4.neighbor.link_layer_address) { + free(mod_ctx->mod_data.ipv4.neighbor.link_layer_address); + } + mod_ctx->mod_data.ipv4.neighbor.link_layer_address = NULL; + mod_ctx->mod_data.ipv4.neighbor.link_layer_set = false; + return error; } void interfaces_interface_ipv4_neighbor_change_ip_free(void* priv) { } + +static int interfaces_interface_ipv4_address_get_link_layer_address(void* priv, sr_session_ctx_t* session, const srpc_change_ctx_t* change_ctx) +{ + int error = 0; + + // ctx + interfaces_ctx_t* ctx = priv; + interfaces_mod_changes_ctx_t* mod_ctx = &ctx->mod_ctx; + + const char* node_name = LYD_NAME(change_ctx->node); + const char* node_value = lyd_get_value(change_ctx->node); + + SRPLG_LOG_INF(PLUGIN_NAME, "Node Name: %s; Previous Value: %s, Value: %s; Operation: %d", node_name, change_ctx->previous_value, node_value, change_ctx->operation); + + // this callback should only be called on CREATED operation + assert(change_ctx->operation == SR_OP_CREATED); + + // set mod changes prefix length + mod_ctx->mod_data.ipv4.neighbor.link_layer_address = strdup(node_value); + if (!mod_ctx->mod_data.ipv4.neighbor.link_layer_address) { + SRPLG_LOG_ERR(PLUGIN_NAME, "Unable to set link-layer-address value for module changes context"); + goto error_out; + } + mod_ctx->mod_data.ipv4.neighbor.link_layer_set = true; + + goto out; + +error_out: + error = -1; + mod_ctx->mod_data.ipv4.neighbor.link_layer_set = false; + +out: + return error; +} \ No newline at end of file diff --git a/src/interfaces/src/plugin/api/interfaces/interface/ipv4/neighbor/change.h b/src/interfaces/src/plugin/api/interfaces/interface/ipv4/neighbor/change.h index 9169ddbc..96fc4108 100644 --- a/src/interfaces/src/plugin/api/interfaces/interface/ipv4/neighbor/change.h +++ b/src/interfaces/src/plugin/api/interfaces/interface/ipv4/neighbor/change.h @@ -7,6 +7,7 @@ int interfaces_interface_ipv4_neighbor_change_link_layer_address_init(void* priv); int interfaces_interface_ipv4_neighbor_change_link_layer_address(void* priv, sr_session_ctx_t* session, const srpc_change_ctx_t* change_ctx); void interfaces_interface_ipv4_neighbor_change_link_layer_address_free(void* priv); + int interfaces_interface_ipv4_neighbor_change_ip_init(void* priv); int interfaces_interface_ipv4_neighbor_change_ip(void* priv, sr_session_ctx_t* session, const srpc_change_ctx_t* change_ctx); void interfaces_interface_ipv4_neighbor_change_ip_free(void* priv); diff --git a/src/interfaces/src/plugin/context.h b/src/interfaces/src/plugin/context.h index f1cdf216..e7b48b0f 100644 --- a/src/interfaces/src/plugin/context.h +++ b/src/interfaces/src/plugin/context.h @@ -36,10 +36,18 @@ struct interfaces_mod_changes_ctx_s { // libnl links data interfaces_nl_ctx_t nl_ctx; - // data + // temporary module changing data struct { - uint8_t prefix_length; - uint8_t prefix_set; ///< prefix_length has been set + struct { + struct { + uint8_t prefix_length; + uint8_t prefix_set; ///< prefix_length has been set + } address; + struct { + char* link_layer_address; + uint8_t link_layer_set; ///< link_layer_address has been set + } neighbor; + } ipv4; } mod_data; }; diff --git a/src/interfaces/src/plugin/subscription/change.c b/src/interfaces/src/plugin/subscription/change.c index 400515be..56674380 100644 --- a/src/interfaces/src/plugin/subscription/change.c +++ b/src/interfaces/src/plugin/subscription/change.c @@ -1,4 +1,5 @@ #include "change.h" +#include "plugin/api/interfaces/interface/ipv4/neighbor/change.h" #include "plugin/common.h" #include "plugin/context.h" @@ -67,9 +68,13 @@ int interfaces_subscription_change_interfaces_interface(sr_session_ctx_t* sessio SRPC_SAFE_CALL_ERR_COND(rc, rc < 0, snprintf(change_xpath_buffer, sizeof(change_xpath_buffer), "%s/ipv4/address/netmask", xpath), error_out); SRPC_SAFE_CALL_ERR(rc, srpc_iterate_changes(ctx, session, change_xpath_buffer, interfaces_interface_ipv4_address_change_netmask, interfaces_change_interface_init, interfaces_change_interface_free), error_out); - // ipv4/neighbor - SRPC_SAFE_CALL_ERR_COND(rc, rc < 0, snprintf(change_xpath_buffer, sizeof(change_xpath_buffer), "%s/ipv4/neighbor", xpath), error_out); - SRPC_SAFE_CALL_ERR(rc, srpc_iterate_changes(ctx, session, change_xpath_buffer, interfaces_interface_ipv4_change_neighbor, interfaces_change_interface_init, interfaces_change_interface_free), error_out); + // ipv4/neighbor/ip + SRPC_SAFE_CALL_ERR_COND(rc, rc < 0, snprintf(change_xpath_buffer, sizeof(change_xpath_buffer), "%s/ipv4/neighbor/ip", xpath), error_out); + SRPC_SAFE_CALL_ERR(rc, srpc_iterate_changes(ctx, session, change_xpath_buffer, interfaces_interface_ipv4_neighbor_change_ip, interfaces_change_interface_init, interfaces_change_interface_free), error_out); + + // ipv4/neighbor/link-layer-address + SRPC_SAFE_CALL_ERR_COND(rc, rc < 0, snprintf(change_xpath_buffer, sizeof(change_xpath_buffer), "%s/ipv4/neighbor/link-layer-address", xpath), error_out); + SRPC_SAFE_CALL_ERR(rc, srpc_iterate_changes(ctx, session, change_xpath_buffer, interfaces_interface_ipv4_neighbor_change_link_layer_address, interfaces_change_interface_init, interfaces_change_interface_free), error_out); } goto out;