From 52002bff61ccdd95a3e69094f8e6a99eaf2c0b32 Mon Sep 17 00:00:00 2001 From: Andrej Kozemcak Date: Thu, 14 Feb 2019 13:15:22 +0100 Subject: Plugin - init NAT Change-Id: I072b3bc018812d9f51cb7269bfdbb98b19db873c Signed-off-by: Andrej Kozemcak --- src/plugins/CMakeLists.txt | 1 + src/plugins/ietf/ietf_nat.c | 532 ++++++++++++++++++++++++++++++++++++++++++++ src/plugins/ietf/ietf_nat.h | 25 +++ src/plugins/sc_plugins.c | 2 + src/plugins/sys_util.c | 87 ++++++++ src/plugins/sys_util.h | 40 ++++ src/scvpp/src/sc_vpp_comm.c | 13 ++ src/scvpp/src/sc_vpp_comm.h | 10 + 8 files changed, 710 insertions(+) create mode 100644 src/plugins/ietf/ietf_nat.c create mode 100644 src/plugins/ietf/ietf_nat.h diff --git a/src/plugins/CMakeLists.txt b/src/plugins/CMakeLists.txt index 72a87bd..d8dba04 100644 --- a/src/plugins/CMakeLists.txt +++ b/src/plugins/CMakeLists.txt @@ -57,6 +57,7 @@ set(PLUGINS_SOURCES sc_model.c sys_util.c ietf/ietf_interface.c + ietf/ietf_nat.c openconfig/openconfig_interfaces.c openconfig/openconfig_local_routing.c ) diff --git a/src/plugins/ietf/ietf_nat.c b/src/plugins/ietf/ietf_nat.c new file mode 100644 index 0000000..86c8570 --- /dev/null +++ b/src/plugins/ietf/ietf_nat.c @@ -0,0 +1,532 @@ +/* + * Copyright (c) 2019 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. + */ + +#include "ietf_nat.h" +#include "sc_vpp_comm.h" +#include "sc_vpp_interface.h" +#include "sc_vpp_nat.h" + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "../sys_util.h" + +static int ietf_nat_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("Module subscribe: %s", module_name); + + return SR_ERR_OK; +} + +/** + * @brief Wrapper struct for VAPI address range payload. + */ +struct address_range_t { + nat44_add_del_address_range_t payload; //< VAPI payload for address range. + bool last_ip_address_set; //< Variable last_ip_address in payload is set. +}; + +// Check input structure, set VAPI payload and call VAPI function to set +// nat44 address range. +static sr_error_t set_address_range(struct address_range_t *address_r) +{ + sr_error_t rc = SR_ERR_OK; +// char tmp_ip1[VPP_IP4_ADDRESS_STRING_LEN]; +// char tmp_ip2[VPP_IP4_ADDRESS_STRING_LEN]; + + ARG_CHECK(SR_ERR_INVAL_ARG, address_r); + + //if end of IP range not provided, then range size = 1 with only first ip + if (!address_r->last_ip_address_set) { + memcpy(&address_r->payload.last_ip_address[0], + &address_r->payload.first_ip_address[0], + VPP_IP4_ADDRESS_LEN); + } + + if (hardntohlu32(address_r->payload.last_ip_address) < + hardntohlu32(address_r->payload.first_ip_address)) { + SRP_LOG_ERR_MSG("End address less than start address"); + return SR_ERR_INVAL_ARG; + } + +// strncpy(tmp_ip1, sc_ntoa(address_r->payload.first_ip_address), +// VPP_IP4_ADDRESS_STRING_LEN); +// strncpy(tmp_ip2, sc_ntoa(address_r->payload.last_ip_address), +// VPP_IP4_ADDRESS_STRING_LEN); +// SRP_LOG_DBG("Fist ip address: %s, last ip address: %s, twice_nat: %u," +// "is_add: %u", tmp_ip1, tmp_ip2, address_r->payload.twice_nat, +// address_r->payload.is_add); + + int rv = nat44_add_del_addr_range(&address_r->payload); + if (0 != rv) { + SRP_LOG_ERR_MSG("Failed set address range."); + rc = SR_ERR_OPERATION_FAILED; + } + + return rc; +} + +// parse leaf from this xpath: +// /ietf-nat:nat/instances/instance[id='%s']/policy[id='%s']/external-ip-address-pool[pool-id='%s']/ +static int parse_instance_policy_external_ip_address_pool( + const sr_val_t *val, struct address_range_t *address_range) +{ + int rc; + char tmp_str[VPP_IP4_PREFIX_STRING_LEN] = {0}; + uint8_t prefix = 0; + + ARG_CHECK2(SR_ERR_INVAL_ARG, val, address_range); + + if (sr_xpath_node_name_eq(val->xpath, "pool-id")) { + SRP_LOG_WRN("%s not supported.", val->xpath); + } else if(sr_xpath_node_name_eq(val->xpath, "external-ip-pool")) { + rc = get_address_from_prefix(tmp_str, val->data.string_val, + VPP_IP4_ADDRESS_STRING_LEN, &prefix); + if (0 != rc) { + SRP_LOG_ERR_MSG("Error translate"); + return SR_ERR_INVAL_ARG; + } + + rc = sc_aton(tmp_str, address_range->payload.first_ip_address, + VPP_IP4_ADDRESS_LEN); + if (0 != rc) { + SRP_LOG_ERR_MSG("Failed convert string IP address to int."); + return SR_ERR_INVAL_ARG; + } + + if (prefix < VPP_IP4_HOST_PREFIX_LEN) { + // External IP pool is represented as IPv4 prefix in YANG module. + // VPP support range from first IPv4 address to last IPv4 address, not prefix. + // In this concept the broadcast IPv4 address of this IPv4 prefix, + // represent last IPv4 address for VPP + get_last_ip_address( + (sc_ipv4_addr*) &address_range->payload.last_ip_address[0], + (sc_ipv4_addr*) &address_range->payload.first_ip_address[0], + prefix); + address_range->last_ip_address_set = true; + } + } + + return SR_ERR_OK; +} + +// XPATH: /ietf-nat:nat/instances/instance[id='%s']/policy[id='%s']/external-ip-address-pool[pool-id='%s']/ +static int instances_instance_policy_external_ip_address_pool_cb( + sr_session_ctx_t *ds, const char *xpath, sr_notif_event_t event, + __attribute__((unused)) void *private_ctx) +{ + sr_error_t rc = SR_ERR_OK; + sr_change_iter_t *it = NULL; + sr_change_oper_t oper; + sr_val_t *old_val = NULL; + sr_val_t *new_val = NULL; + bool create = false; + bool delete = false; + struct address_range_t new_address_r = {0}; + struct address_range_t old_address_r = {0}; + + ARG_CHECK2(SR_ERR_INVAL_ARG, ds, xpath); + + new_address_r.payload.vrf_id = ~0; + old_address_r.payload.vrf_id = ~0; + + SRP_LOG_DBG("'%s' modified, event=%d", xpath, event); + + 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) { + + SRP_LOG_DBG("A change detected in '%s', op=%d", + new_val ? new_val->xpath : old_val->xpath, oper); + + switch (oper) { + case SR_OP_CREATED: + create = true; + rc = parse_instance_policy_external_ip_address_pool(new_val, + &new_address_r); + break; + + case SR_OP_MODIFIED: + delete = true; + rc = parse_instance_policy_external_ip_address_pool(old_val, + &old_address_r); + if (SR_ERR_OK != rc) { + break; + } + + create = true; + rc = parse_instance_policy_external_ip_address_pool(new_val, + &new_address_r); + break; + + case SR_OP_MOVED: + break; + + case SR_OP_DELETED: + delete = true; + rc = parse_instance_policy_external_ip_address_pool(old_val, + &old_address_r); + break; + } + + sr_free_val(old_val); + sr_free_val(new_val); + + if (SR_ERR_OK != rc) { + rc = SR_ERR_OPERATION_FAILED; + goto error; + } + } + + if (delete) { + old_address_r.payload.is_add = 0; + rc = set_address_range(&old_address_r); + if (SR_ERR_OK != rc) { + goto error; + } + } + + if (create) { + new_address_r.payload.is_add = 1; + rc = set_address_range(&new_address_r); + if (SR_ERR_OK != rc) { + goto error; + } + } + +error: + sr_free_change_iter(it); + return rc; +} + +enum mapping_type { + STATIC, + DYNAMIC_IMPLICIT, + DYNAMIC_EXPLICIT, + UNKNOWN, +}; + +/** + * @brief Wrapper struct for VAPI static mapping payload. + */ +struct static_mapping_t { + enum mapping_type mtype; //< Mapping type + bool local_ip_address_set; //< Variable are set in payload. + bool external_ip_address_set; //< Variable are set in payload. + bool protocol_set; //< Variable are set in payload. + bool local_port_set; //< Variable are set in payload. + bool external_port_set; //< Variable are set in payload. + bool external_sw_if_index_set; //< Variable are set in payload. + bool vrf_id_set; //< Variable are set in payload. + bool twice_nat_set; //< Variable are set in payload. + nat44_add_del_static_mapping_t payload; //< VAPI payload for static mapping +}; + +// Check input structure, set VAPI payload and call VAPI function to set +// nat44 static mapping. +static sr_error_t set_static_mapping(struct static_mapping_t *mapping) +{ + int rc = 0; +// char tmp_ip1[VPP_IP4_ADDRESS_STRING_LEN]; +// char tmp_ip2[VPP_IP4_ADDRESS_STRING_LEN]; + + ARG_CHECK(SR_ERR_INVAL_ARG, mapping); + + if ((mapping->local_port_set != mapping->external_port_set) || + !mapping->local_ip_address_set || !mapping->external_ip_address_set) { + SRP_LOG_ERR_MSG("NAT44 parameter missing."); + + return SR_ERR_VALIDATION_FAILED; + } + + if (!mapping->local_port_set && !mapping->external_port_set) { + mapping->payload.addr_only= 1; + mapping->payload.twice_nat = 0; + } else { + mapping->payload.addr_only= 0; + mapping->payload.twice_nat = 1; + if (!mapping->protocol_set) { + + SRP_LOG_ERR_MSG("NAT44 protocol missing."); + return SR_ERR_VALIDATION_FAILED; + } + } + + mapping->payload.external_sw_if_index = ~0; + +// strncpy(tmp_ip1, sc_ntoa(mapping->payload.local_ip_address), +// VPP_IP4_ADDRESS_STRING_LEN); +// strncpy(tmp_ip2, sc_ntoa(mapping->payload.external_ip_address), +// VPP_IP4_ADDRESS_STRING_LEN); +// SRP_LOG_DBG("Local ip address: %s, external ip address: %s, addr_only: %u," +// " protocol: %u, local port: %u, external port: %u, twice_nat: %u," +// "is_add: %u", tmp_ip1, tmp_ip2, mapping->payload.addr_only, +// mapping->payload.protocol, mapping->payload.local_port, +// mapping->payload.external_port, mapping->payload.twice_nat, +// mapping->payload.is_add); + + rc = nat44_add_del_static_mapping(&mapping->payload); + if (0 != rc) { + SRP_LOG_ERR_MSG("Failed set static mapping"); + return SR_ERR_OPERATION_FAILED; + } + + return SR_ERR_OK; +} + +// parse leaf from this xpath: +// /ietf-nat:nat/instances/instance[id='%s']/mapping-table/mapping-entry[index='%s']/ +static int parse_instance_mapping_table_mapping_entry( + const sr_val_t *val, + struct static_mapping_t *mapping) +{ + int rc; + char tmp_str[VPP_IP4_PREFIX_STRING_LEN] = {0}; + + ARG_CHECK2(SR_ERR_INVAL_ARG, val, mapping); + + sr_xpath_ctx_t state = {0}; + + if(sr_xpath_node_name_eq(val->xpath, "type")) { + if (!strncmp("static", val->data.string_val, strlen("static"))) { + mapping->mtype = STATIC; + } else if (!strncmp("dynamic-implicit", val->data.string_val, + strlen("dynamic-implicit"))) { + mapping->mtype = DYNAMIC_IMPLICIT; + } else if (!strncmp("dynamic-explicit", val->data.string_val, + strlen("dynamic-explicit"))) { + mapping->mtype = DYNAMIC_EXPLICIT; + } + } else if(sr_xpath_node_name_eq(val->xpath, "transport-protocol")) { + if (SR_UINT8_T != val->type) { + SRP_LOG_ERR("Wrong transport-protocol, type, current type: %d.", + val->type); + return SR_ERR_INVAL_ARG; + } + + mapping->payload.protocol = val->data.uint8_val; + mapping->protocol_set = true; + } else if(sr_xpath_node_name_eq(val->xpath, "internal-src-address")) { + if (SR_STRING_T != val->type) { + SRP_LOG_ERR("Wrong internal-src-address, type, current type: %d.", + val->type); + return SR_ERR_INVAL_ARG; + } + + rc = get_address_from_prefix(tmp_str, val->data.string_val, + VPP_IP4_PREFIX_STRING_LEN, NULL); + if (0 != rc) { + SRP_LOG_ERR_MSG("Error translate"); + return SR_ERR_INVAL_ARG; + } + + rc = sc_aton(tmp_str, mapping->payload.local_ip_address, + VPP_IP4_ADDRESS_LEN); + if (0 != rc) { + SRP_LOG_ERR_MSG("Failed convert string IP address to int."); + return SR_ERR_INVAL_ARG; + } + + mapping->local_ip_address_set = true; + } else if(sr_xpath_node_name_eq(val->xpath, "external-src-address")) { + if (SR_STRING_T != val->type) { + SRP_LOG_ERR("Wrong external-src-address, type, current type: %d.", + val->type); + return SR_ERR_INVAL_ARG; + } + + rc = get_address_from_prefix(tmp_str, val->data.string_val, + VPP_IP4_ADDRESS_STRING_LEN, NULL); + if (0 != rc) { + SRP_LOG_ERR_MSG("Error translate"); + return SR_ERR_INVAL_ARG; + } + + rc = sc_aton(tmp_str, mapping->payload.external_ip_address, + VPP_IP4_ADDRESS_LEN); + if (0 != rc) { + SRP_LOG_ERR_MSG("Failed convert string IP address to int."); + return SR_ERR_INVAL_ARG; + } + + mapping->external_ip_address_set = true; + } else if (sr_xpath_node(val->xpath, "internal-src-port", &state)) { + sr_xpath_recover(&state); + if(sr_xpath_node_name_eq(val->xpath, "start-port-number")) { + mapping->local_port_set = true; + mapping->payload.local_port = val->data.uint16_val; + } + } else if (sr_xpath_node(val->xpath, "external-src-port", &state)) { + sr_xpath_recover(&state); + if(sr_xpath_node_name_eq(val->xpath, "start-port-number")) { + mapping->external_port_set = true; + mapping->payload.external_port = val->data.uint16_val; + } + } + + return SR_ERR_OK; +} + +// XPATH: /ietf-nat:nat/instances/instance[id='%s']/mapping-table/mapping-entry[index='%s']/ +static int instances_instance_mapping_table_mapping_entry_cb( + sr_session_ctx_t *ds, const char *xpath, sr_notif_event_t event, + __attribute__((unused)) void *private_ctx) +{ + sr_error_t rc = SR_ERR_OK; + sr_change_iter_t *it = NULL; + sr_change_oper_t oper; + sr_val_t *old_val = NULL; + sr_val_t *new_val = NULL; + bool create = false; + bool delete = false; + struct static_mapping_t new_mapping = {0}; + struct static_mapping_t old_mapping = {0}; + + ARG_CHECK2(SR_ERR_INVAL_ARG, ds, xpath); + + new_mapping.mtype = UNKNOWN; + old_mapping.mtype = UNKNOWN; + + SRP_LOG_DBG("'%s' modified, event=%d", xpath, event); + + 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) { + + SRP_LOG_DBG("A change detected in '%s', op=%d", + new_val ? new_val->xpath : old_val->xpath, oper); + + switch (oper) { + case SR_OP_CREATED: + create = true; + rc = parse_instance_mapping_table_mapping_entry(new_val, + &new_mapping); + break; + + case SR_OP_MODIFIED: + delete = true; + rc = parse_instance_mapping_table_mapping_entry(old_val, + &old_mapping); + if (SR_ERR_OK != rc) { + break; + } + + create = true; + rc = parse_instance_mapping_table_mapping_entry(new_val, + &new_mapping); + break; + + case SR_OP_MOVED: + break; + + case SR_OP_DELETED: + delete = true; + rc = parse_instance_mapping_table_mapping_entry(old_val, + &old_mapping); + break; + } + + sr_free_val(old_val); + sr_free_val(new_val); + + if (SR_ERR_OK != rc) { + rc = SR_ERR_OPERATION_FAILED; + goto error; + } + } + + if (delete) { + old_mapping.payload.is_add = 0; + if (STATIC == old_mapping.mtype) { + rc = set_static_mapping(&old_mapping); + if (SR_ERR_OK != rc) { + goto error; + } + } + } + + if (create) { + new_mapping.payload.is_add = 1; + if (STATIC == new_mapping.mtype) { + rc = set_static_mapping(&new_mapping); + if (SR_ERR_OK != rc) { + goto error; + } + } + } + +error: + sr_free_change_iter(it); + return rc; +} + +const xpath_t ietf_nat_xpaths[IETF_NAT_SIZE] = { + { + .xpath = "ietf-nat", + .method = MODULE, + .datastore = SR_DS_RUNNING, + .cb.mcb = ietf_nat_mod_cb, + .private_ctx = NULL, + .priority = 0, + .opts = SR_SUBSCR_EV_ENABLED | SR_SUBSCR_APPLY_ONLY | SR_SUBSCR_CTX_REUSE + }, + { + .xpath = "/ietf-nat:nat/instances/instance/policy/external-ip-address-pool", + .method = XPATH, + .datastore = SR_DS_RUNNING, + .cb.scb = instances_instance_policy_external_ip_address_pool_cb, + .private_ctx = NULL, + .priority = 0, + .opts = SR_SUBSCR_CTX_REUSE + }, + { + .xpath = "/ietf-nat:nat/instances/instance/mapping-table/mapping-entry", + .method = XPATH, + .datastore = SR_DS_RUNNING, + .cb.scb = instances_instance_mapping_table_mapping_entry_cb, + .private_ctx = NULL, + .priority = 0, + .opts = SR_SUBSCR_CTX_REUSE + }, +}; diff --git a/src/plugins/ietf/ietf_nat.h b/src/plugins/ietf/ietf_nat.h new file mode 100644 index 0000000..7495209 --- /dev/null +++ b/src/plugins/ietf/ietf_nat.h @@ -0,0 +1,25 @@ +/* + * Copyright (c) 2019 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 __IETF_NAT_H__ +#define __IETF_NAT_H__ + +#include "../sc_model.h" + +#define IETF_NAT_SIZE 3 +extern const xpath_t ietf_nat_xpaths[IETF_NAT_SIZE]; + +#endif diff --git a/src/plugins/sc_plugins.c b/src/plugins/sc_plugins.c index 093939c..87ea2d7 100644 --- a/src/plugins/sc_plugins.c +++ b/src/plugins/sc_plugins.c @@ -17,6 +17,7 @@ #include "sc_model.h" #include "ietf/ietf_interface.h" +#include "ietf/ietf_nat.h" #include "openconfig/openconfig_interfaces.h" #include "openconfig/openconfig_local_routing.h" @@ -36,6 +37,7 @@ int sr_plugin_init_cb(sr_session_ctx_t *session, void **private_ctx) /* Use the same sr_subscription_ctx for all models */ model_register(&plugin_main, ietf_interfaces_xpaths, IETF_INTERFACES_SIZE); + model_register(&plugin_main, ietf_nat_xpaths, IETF_NAT_SIZE); model_register(&plugin_main, oc_interfaces_xpaths, OC_INTERFACES_SIZE); model_register(&plugin_main, oc_local_routing_xpaths, OC_LROUTING_SIZE); diff --git a/src/plugins/sys_util.c b/src/plugins/sys_util.c index 7bd0937..a3ee0c9 100644 --- a/src/plugins/sys_util.c +++ b/src/plugins/sys_util.c @@ -81,3 +81,90 @@ int ip_prefix_split(const char* ip_prefix) //return mask length return mask; } + +/** + * @brief Get IPv4 host address from IPv4 prefix. + * + * @param[out] dst Host IPv4 address. + * @param[in] src IPv4 Prefix. + * @param[in] length dst buffer length. + * @param[out] prefix Get Prefix length, optional value. Can be NULL. + * @return -1 when failure, 0 on success. + */ +int get_address_from_prefix(char *dst, const char *src, size_t length, + uint8_t *prefix_length) +{ + ARG_CHECK2(-1, src, dst); + + size_t size = 0; + char *p = strchr(src, '/'); + if (NULL == p) { + return -1; + } + + size = p - src; + + // + 1, need size for \0 + if ((size + 1) > length) { + return -1; + } + + strncpy(dst, src, size); + + if (NULL != prefix_length) { + *prefix_length = atoi(++p); + } + + return 0; +} + +/** + * @brief Get IPv4 broadcast IP address form IPv4 network address. + * + * @param[out] broadcat Broadcast Ipv4 address. + * @param[in] network Network IPv4 address. + * @param[in] prefix Prefix number. + * @return -1 when failure, 0 on success. + */ +int get_network_broadcast(sc_ipv4_addr *broadcast, const sc_ipv4_addr *network, + uint8_t prefix_length) +{ + uint8_t mask = ~0; + uint8_t tmp_p = prefix_length; + int i; + + ARG_CHECK2(-1, network, broadcast); + + if (32 < prefix_length) { + SRP_LOG_ERR_MSG("Prefix length to big."); + return -1; + } + + for (i = 0; i < 4 ; i++) { + broadcast->address[i] = network->address[i] | + (mask >> (tmp_p > 8 ? 8 : tmp_p)); + if (tmp_p >= 8) { + tmp_p -= 8; + } else { + tmp_p = 0; + } + } + + return 0; +} + +/** + * @brief Get last IPv4 address from the IP range. + * + * @param[out] last_ip_address Last Ipv4 address. + * @param[in] first_ip_address First IPv4 address. + * @param[in] prefix Prefix number. + * @return -1 when failure, 0 on success. + */ +int get_last_ip_address(sc_ipv4_addr* last_ip_address, + const sc_ipv4_addr* first_ip_address, + uint8_t prefix_length) +{ + return get_network_broadcast(last_ip_address, first_ip_address, + prefix_length); +} diff --git a/src/plugins/sys_util.h b/src/plugins/sys_util.h index 6c227c3..d449712 100644 --- a/src/plugins/sys_util.h +++ b/src/plugins/sys_util.h @@ -34,4 +34,44 @@ void log_recv_event(sr_notif_event_t event, const char *msg); void log_recv_oper(sr_change_oper_t oper, const char *msg); int ip_prefix_split(const char* ip_prefix); +/** + * @brief Get IPv4 host address from IPv4 prefix. + * + * @param[out] dst Host IPv4 address. + * @param[in] src IPv4 Prefix. + * @param[in] length dst buffer length. + * @param[out] prefix Get Prefix length, optional value. Can be NULL. + * @return -1 when failure, 0 on success. + */ +int get_address_from_prefix(char* dst, const char* src, size_t length, + uint8_t* prefix_length); + +typedef struct +{ + uint8_t address[4]; +} sc_ipv4_addr; + +/** + * @brief Get IPv4 broadcast IP address form IPv4 network address. + * + * @param[out] broadcat Broadcast Ipv4 address. + * @param[in] network Network IPv4 address. + * @param[in] prefix Prefix number. + * @return -1 when failure, 0 on success. + */ +int get_network_broadcast(sc_ipv4_addr *broadcast, const sc_ipv4_addr *network, + uint8_t prefix_length); + +/** + * @brief Get last IPv4 address from the IP range. + * + * @param[out] last_ip_address Last Ipv4 address. + * @param[in] first_ip_address First IPv4 address. + * @param[in] prefix Prefix number. + * @return -1 when failure, 0 on success. + */ +int get_last_ip_address(sc_ipv4_addr *last_ip_address, + const sc_ipv4_addr *first_ip_address, + uint8_t prefix_length); + #endif /* __SYS_UTIL_H__ */ diff --git a/src/scvpp/src/sc_vpp_comm.c b/src/scvpp/src/sc_vpp_comm.c index 241b4ce..cd0b035 100644 --- a/src/scvpp/src/sc_vpp_comm.c +++ b/src/scvpp/src/sc_vpp_comm.c @@ -98,3 +98,16 @@ char* sc_ntoa(const u8 * buf) memcpy(&addr, buf, sizeof(addr)); return inet_ntoa(addr); } + +/** + * @brief Function converts the u8 array from network byte order to host byte order. + * + * @param[in] host IPv4 address. + * @return host byte order value. + */ +uint32_t hardntohlu32(uint8_t host[4]) +{ + uint32_t tmp = host[3] | host[2] | host[1] | host[0]; + + return ntohl(tmp); +} diff --git a/src/scvpp/src/sc_vpp_comm.h b/src/scvpp/src/sc_vpp_comm.h index 2405259..eeeaaf9 100644 --- a/src/scvpp/src/sc_vpp_comm.h +++ b/src/scvpp/src/sc_vpp_comm.h @@ -31,6 +31,8 @@ DEFINE_VAPI_MSG_IDS_VPE_API_JSON; #define VPP_IP4_ADDRESS_LEN 4 #define VPP_IP6_ADDRESS_LEN 16 #define VPP_IP4_ADDRESS_STRING_LEN 16 +#define VPP_IP4_PREFIX_STRING_LEN 19 +#define VPP_IP4_HOST_PREFIX_LEN 32 #define VPP_IP6_ADDRESS_STRING_LEN 46 #define VPP_MAC_ADDRESS_LEN 8 #define VPP_TAG_LEN VPP_INTFC_NAME_LEN @@ -112,6 +114,14 @@ api_name##_cb (vapi_ctx_t ctx, void *caller_ctx, vapi_error_e rv, bool is_last, int sc_aton(const char *cp, u8 * buf, size_t length); char * sc_ntoa(const u8 * buf); +/** + * @brief Function converts the u8 array from network byte order to host byte order. + * + * @param[in] host IPv4 address. + * @return host byte order value. + */ +uint32_t hardntohlu32(uint8_t host[4]); + /* * VPP */ -- cgit 1.2.3-korg