static void add_nla_stream_to_msg(struct nl_msg *msg, void *nla, size_t nla_len) { struct nlattr *tail; struct nlmsghdr *hdr; LOG_DBG_("%s: Appending %u bytes of user defined attributes\n", __func__, nla_len); hdr = nlmsg_hdr(msg); tail = nlmsg_tail(hdr); /* nla is assumed to be padded correctly, * so we dont bother with padding */ memcpy(tail, nla, nla_len); hdr->nlmsg_len += nla_len; }
cps_api_return_code_t nas_os_update_route (cps_api_object_t obj, msg_type m_type) { static char buff[NL_RT_MSG_BUFFER_LEN]; // Allocate from DS char addr_str[INET6_ADDRSTRLEN]; memset(buff,0,sizeof(buff)); cps_api_object_attr_t prefix = cps_api_object_attr_get(obj, BASE_ROUTE_OBJ_ENTRY_ROUTE_PREFIX); cps_api_object_attr_t af = cps_api_object_attr_get(obj, BASE_ROUTE_OBJ_ENTRY_AF); cps_api_object_attr_t nh_count = cps_api_object_attr_get(obj, BASE_ROUTE_OBJ_ENTRY_NH_COUNT); cps_api_object_attr_t pref_len = cps_api_object_attr_get(obj, BASE_ROUTE_OBJ_ENTRY_PREFIX_LEN); if (prefix == CPS_API_ATTR_NULL || af == CPS_API_ATTR_NULL || pref_len == CPS_API_ATTR_NULL || (m_type != NAS_RT_DEL && nh_count == CPS_API_ATTR_NULL)) { EV_LOG(ERR, NAS_OS, ev_log_s_CRITICAL, "ROUTE-UPD", "Missing route params"); return cps_api_ret_code_ERR; } struct nlmsghdr *nlh = (struct nlmsghdr *) nlmsg_reserve((struct nlmsghdr *)buff,sizeof(buff),sizeof(struct nlmsghdr)); struct rtmsg * rm = (struct rtmsg *) nlmsg_reserve(nlh,sizeof(buff),sizeof(struct rtmsg)); uint16_t flags = nas_os_get_nl_flags(m_type); uint16_t type = (m_type == NAS_RT_DEL)?RTM_DELROUTE:RTM_NEWROUTE; nas_os_pack_nl_hdr(nlh, type, flags); rm->rtm_table = RT_TABLE_MAIN; rm->rtm_protocol = RTPROT_UNSPEC; // This could be assigned to correct owner in future /* For route delete, initialize scope to no-where and * this will get updated to link when Nh addr/ifx is provided. */ if (type != RTM_DELROUTE) rm->rtm_scope = RT_SCOPE_UNIVERSE; else rm->rtm_scope = RT_SCOPE_NOWHERE; rm->rtm_type = RTN_UNICAST; rm->rtm_dst_len = cps_api_object_attr_data_u32(pref_len); rm->rtm_family = (unsigned char) cps_api_object_attr_data_u32(af); uint32_t addr_len = (rm->rtm_family == AF_INET)?HAL_INET4_LEN:HAL_INET6_LEN; nlmsg_add_attr(nlh,sizeof(buff),RTA_DST,cps_api_object_attr_data_bin(prefix),addr_len); uint32_t nhc = 0; if (nh_count != CPS_API_ATTR_NULL) nhc = cps_api_object_attr_data_u32(nh_count); EV_LOG(INFO, NAS_OS,2,"ROUTE-UPD","NH count:%d family:%s msg:%s for prefix:%s len:%d scope:%d", nhc, ((rm->rtm_family == AF_INET) ? "IPv4" : "IPv6"), ((m_type == NAS_RT_ADD) ? "Route-Add" : ((m_type == NAS_RT_DEL) ? "Route-Del" : "Route-Set")), ((rm->rtm_family == AF_INET) ? (inet_ntop(rm->rtm_family, cps_api_object_attr_data_bin(prefix), addr_str, INET_ADDRSTRLEN)) : (inet_ntop(rm->rtm_family, cps_api_object_attr_data_bin(prefix), addr_str, INET6_ADDRSTRLEN))), rm->rtm_dst_len, rm->rtm_scope); if (nhc == 1) { cps_api_attr_id_t ids[3] = { BASE_ROUTE_OBJ_ENTRY_NH_LIST, 0, BASE_ROUTE_OBJ_ENTRY_NH_LIST_NH_ADDR}; const int ids_len = sizeof(ids)/sizeof(*ids); cps_api_object_attr_t gw = cps_api_object_e_get(obj,ids,ids_len); if (gw != CPS_API_ATTR_NULL) { nlmsg_add_attr(nlh,sizeof(buff),RTA_GATEWAY,cps_api_object_attr_data_bin(gw),addr_len); rm->rtm_scope = RT_SCOPE_UNIVERSE; // set scope to universe when gateway is specified EV_LOG(INFO, NAS_OS, 2,"ROUTE-UPD","NH:%s scope:%d", ((rm->rtm_family == AF_INET) ? (inet_ntop(rm->rtm_family, cps_api_object_attr_data_bin(gw), addr_str, INET_ADDRSTRLEN)) : (inet_ntop(rm->rtm_family, cps_api_object_attr_data_bin(gw), addr_str, INET6_ADDRSTRLEN))), rm->rtm_scope); } else { EV_LOG(INFO, NAS_OS, ev_log_s_MINOR, "ROUTE-UPD", "Missing Gateway, could be intf route"); /* * This could be an interface route, do not return from here! */ } ids[2] = BASE_ROUTE_OBJ_ENTRY_NH_LIST_IFINDEX; cps_api_object_attr_t gwix = cps_api_object_e_get(obj,ids,ids_len); if (gwix != CPS_API_ATTR_NULL) { if (gw == CPS_API_ATTR_NULL) { rm->rtm_scope = RT_SCOPE_LINK; } EV_LOG(INFO, NAS_OS,2,"ROUTE-UPD","out-intf: %d scope:%d", (int)cps_api_object_attr_data_u32(gwix), rm->rtm_scope); nas_nl_add_attr_int(nlh,sizeof(buff),RTA_OIF,gwix); } ids[2] = BASE_ROUTE_OBJ_ENTRY_NH_LIST_WEIGHT; cps_api_object_attr_t weight = cps_api_object_e_get(obj,ids,ids_len); if (weight != CPS_API_ATTR_NULL) nas_nl_add_attr_int(nlh,sizeof(buff),RTA_PRIORITY,weight); } else if (nhc > 1){ struct nlattr * attr_nh = nlmsg_nested_start(nlh, sizeof(buff)); attr_nh->nla_len = 0; attr_nh->nla_type = RTA_MULTIPATH; size_t ix = 0; for (ix = 0; ix < nhc ; ++ix) { struct rtnexthop * rtnh = (struct rtnexthop * )nlmsg_reserve(nlh,sizeof(buff), sizeof(struct rtnexthop)); memset(rtnh,0,sizeof(*rtnh)); cps_api_attr_id_t ids[3] = { BASE_ROUTE_OBJ_ENTRY_NH_LIST, ix, BASE_ROUTE_OBJ_ENTRY_NH_LIST_NH_ADDR}; const int ids_len = sizeof(ids)/sizeof(*ids); cps_api_object_attr_t attr = cps_api_object_e_get(obj,ids,ids_len); if (attr != CPS_API_ATTR_NULL) { nlmsg_add_attr(nlh,sizeof(buff),RTA_GATEWAY, cps_api_object_attr_data_bin(attr),addr_len); rm->rtm_scope = RT_SCOPE_UNIVERSE; // set scope to universe when gateway is specified EV_LOG(INFO, NAS_OS,2,"ROUTE-UPD","MP-NH:%d %s scope:%d",ix, ((rm->rtm_family == AF_INET) ? (inet_ntop(rm->rtm_family, cps_api_object_attr_data_bin(attr), addr_str, INET_ADDRSTRLEN)) : (inet_ntop(rm->rtm_family, cps_api_object_attr_data_bin(attr), addr_str, INET6_ADDRSTRLEN))), rm->rtm_scope); } else { EV_LOG(ERR, NAS_OS, ev_log_s_CRITICAL, "ROUTE-UPD", "Error - Missing Gateway"); return cps_api_ret_code_ERR; } ids[2] = BASE_ROUTE_OBJ_ENTRY_NH_LIST_IFINDEX; attr = cps_api_object_e_get(obj,ids,ids_len); if (attr != CPS_API_ATTR_NULL) rtnh->rtnh_ifindex = (int)cps_api_object_attr_data_u32(attr); ids[2] = BASE_ROUTE_OBJ_ENTRY_NH_LIST_WEIGHT; attr = cps_api_object_e_get(obj,ids,ids_len); if (attr != CPS_API_ATTR_NULL) rtnh->rtnh_hops = (char)cps_api_object_attr_data_u32(attr); rtnh->rtnh_len = (char*)nlmsg_tail(nlh) - (char*)rtnh; } nlmsg_nested_end(nlh,attr_nh); } t_std_error rc = nl_do_set_request(nas_nl_sock_T_ROUTE,nlh,buff,sizeof(buff)); int err_code = STD_ERR_EXT_PRIV (rc); EV_LOG(INFO, NAS_OS,2,"ROUTE-UPD","Netlink error_code %d", err_code); /* * Return success if the error is exist, in case of addition, or * no-exist, in case of deletion. This is because, kernel might have * deleted the route entries (when interface goes down) but has not sent netlink * events for those routes and RTM is trying to delete after that. * Similarly, during ip address configuration, kernel may add the routes * before RTM tries to configure kernel. * */ if(err_code == ESRCH || err_code == EEXIST ) { EV_LOG(INFO, NAS_OS,2,"ROUTE-UPD","No such process or Entry already exists"); /* * Kernel may or may not have the routes but NAS routing needs to be informed * as is from kernel netlink to program NPU for the route addition/deletion to * ensure stale routes are cleaned */ if(err_code == ESRCH) nas_os_publish_route(RTM_DELROUTE, obj); else nas_os_publish_route(RTM_NEWROUTE, obj); rc = STD_ERR_OK; } return rc; }
static cps_api_return_code_t _op(cps_api_operation_types_t op,void * context, cps_api_object_t obj, cps_api_object_t prev) { char buff[1024]; memset(buff,0,sizeof(buff)); cps_api_object_attr_t list[cps_api_if_ROUTE_A_MAX]; cps_api_object_attr_fill_list(obj,0,list,sizeof(list)/sizeof(*list)); if (list[cps_api_if_ROUTE_A_PREFIX]==NULL) return cps_api_ret_code_ERR; if (list[cps_api_if_ROUTE_A_PREFIX_LEN]==NULL) return cps_api_ret_code_ERR; if (list[cps_api_if_ROUTE_A_FAMILY]==NULL) return cps_api_ret_code_ERR; uint32_t prefix_len = cps_api_object_attr_data_u32(list[cps_api_if_ROUTE_A_PREFIX_LEN]); struct nlmsghdr *nlh = (struct nlmsghdr *) nlmsg_reserve((struct nlmsghdr *)buff,sizeof(buff),sizeof(struct nlmsghdr)); struct rtmsg * rm = (struct rtmsg *) nlmsg_reserve(nlh,sizeof(buff),sizeof(struct rtmsg)); //sizeof structure + attrs nlh->nlmsg_len nlh->nlmsg_pid = 0; nlh->nlmsg_seq = 0; nlh->nlmsg_type =RTM_NEWROUTE; nlh->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK ; if (op==cps_api_oper_CREATE) { nlh->nlmsg_flags |= NLM_F_CREATE | NLM_F_EXCL; } if (op==cps_api_oper_SET) { nlh->nlmsg_flags |=NLM_F_REPLACE; } if (op==cps_api_oper_DELETE) { nlh->nlmsg_type =RTM_DELROUTE; } rm->rtm_table = RT_TABLE_MAIN; rm->rtm_protocol = RTPROT_BOOT; rm->rtm_dst_len = prefix_len; rm->rtm_scope = RT_SCOPE_UNIVERSE; rm->rtm_type = RTN_UNICAST; rm->rtm_family = (unsigned char) cps_api_object_attr_data_u32(list[cps_api_if_ROUTE_A_FAMILY]); EV_LOG(INFO,NETLINK,3,"ROUTEADD","Family is %d",rm->rtm_family); if (list[cps_api_if_ROUTE_A_PREFIX]!=NULL) nas_nl_add_attr_ip(nlh,sizeof(buff),RTA_DST,list[cps_api_if_ROUTE_A_PREFIX]); if (list[cps_api_if_ROUTE_A_HOP_COUNT]==NULL) return cps_api_ret_code_ERR; uint32_t hc = cps_api_object_attr_data_u32(list[cps_api_if_ROUTE_A_HOP_COUNT]); EV_LOG(INFO,NETLINK,3,"ROUTEADD","hopcount is %d",hc); if (hc==1) { cps_api_attr_id_t ids[3] = { cps_api_if_ROUTE_A_NH, 0, cps_api_if_ROUTE_A_NEXT_HOP_ADDR}; const int ids_len = sizeof(ids)/sizeof(*ids); cps_api_object_attr_t gw = cps_api_object_e_get(obj,ids,ids_len); EV_LOG(INFO,NETLINK,3,"ROUTEADD","nh addr is %d",(int)(size_t)gw); if (gw!=NULL) nas_nl_add_attr_ip(nlh,sizeof(buff),RTA_GATEWAY,gw); ids[2] = cps_api_if_ROUTE_A_NH_IFINDEX; cps_api_object_attr_t gwix = cps_api_object_e_get(obj,ids,ids_len); EV_LOG(INFO,NETLINK,3,"ROUTEADD","nh index is %d",(int)(size_t)gwix); if (gwix!=NULL) nas_nl_add_attr_int(nlh,sizeof(buff),RTA_OIF,gwix); ids[2] = cps_api_if_ROUTE_A_NEXT_HOP_WEIGHT; cps_api_object_attr_t weight = cps_api_object_e_get(obj,ids,ids_len); if (weight!=NULL) nas_nl_add_attr_int(nlh,sizeof(buff),RTA_PRIORITY,weight); } else { struct nlattr * attr_nh = nlmsg_nested_start(nlh, sizeof(buff)); attr_nh->nla_len = 0; attr_nh->nla_type = RTA_MULTIPATH; size_t ix = 0; for (ix = 0; ix < hc ; ++ix) { struct rtnexthop * rtnh = (struct rtnexthop * )nlmsg_reserve(nlh,sizeof(buff), sizeof(struct rtnexthop)); memset(rtnh,0,sizeof(*rtnh)); cps_api_attr_id_t ids[3] = { cps_api_if_ROUTE_A_NH, ix, cps_api_if_ROUTE_A_NEXT_HOP_ADDR}; const int ids_len = sizeof(ids)/sizeof(*ids); cps_api_object_attr_t attr = cps_api_object_e_get(obj,ids,ids_len); if (attr!=NULL) nas_nl_add_attr_ip(nlh,sizeof(buff),RTA_GATEWAY,attr); ids[2] = cps_api_if_ROUTE_A_NH_IFINDEX; attr = cps_api_object_e_get(obj,ids,ids_len); if (attr!=NULL) rtnh->rtnh_ifindex = (int)cps_api_object_attr_data_u32(attr); ids[2] = cps_api_if_ROUTE_A_NEXT_HOP_WEIGHT; attr = cps_api_object_e_get(obj,ids,ids_len); if (attr!=NULL) rtnh->rtnh_hops = (char)cps_api_object_attr_data_u32(attr); ids[2] = cps_api_if_ROUTE_A_NEXT_HOP_FLAGS; attr = cps_api_object_e_get(obj,ids,ids_len); if (attr!=NULL) rtnh->rtnh_flags = (char)cps_api_object_attr_data_u32(attr); rtnh->rtnh_len = (char*)nlmsg_tail(nlh) - (char*)rtnh; } nlmsg_nested_end(nlh,attr_nh); } return (cps_api_return_code_t) nl_do_set_request(nas_nl_sock_T_ROUTE,nlh,buff,sizeof(buff)); }