static int handle_cmd(struct sk_buff *skb, struct genl_info *info) { struct sk_buff *rep_buf; struct nlmsghdr *rep_nlh; struct nlmsghdr *req_nlh = info->nlhdr; struct tipc_genlmsghdr *req_userhdr = info->userhdr; int hdr_space = nlmsg_total_size(GENL_HDRLEN + TIPC_GENL_HDRLEN); u16 cmd; if ((req_userhdr->cmd & 0xC000) && (!capable(CAP_NET_ADMIN))) cmd = TIPC_CMD_NOT_NET_ADMIN; else cmd = req_userhdr->cmd; rep_buf = tipc_cfg_do_cmd(req_userhdr->dest, cmd, nlmsg_data(req_nlh) + GENL_HDRLEN + TIPC_GENL_HDRLEN, nlmsg_attrlen(req_nlh, GENL_HDRLEN + TIPC_GENL_HDRLEN), hdr_space); if (rep_buf) { skb_push(rep_buf, hdr_space); rep_nlh = nlmsg_hdr(rep_buf); memcpy(rep_nlh, req_nlh, hdr_space); rep_nlh->nlmsg_len = rep_buf->len; genlmsg_unicast(&init_net, rep_buf, NETLINK_CB(skb).portid); } return 0; }
static int parse_reply (struct nl_msg *msg, void *arg) { struct nlmsghdr *n = nlmsg_hdr (msg); struct nlattr *tb[XFRMA_MAX + 1]; struct xfrm_userpolicy_info *xpinfo = NULL; if (n->nlmsg_type != XFRM_MSG_NEWPOLICY) { g_warning ("msg type %d not NEWPOLICY", n->nlmsg_type); return NL_SKIP; } /* Netlink message header is followed by 'struct xfrm_userpolicy_info' and * then the attributes. */ if (!nlmsg_valid_hdr (n, sizeof (struct xfrm_userpolicy_info))) { g_warning ("msg too short"); return -NLE_MSG_TOOSHORT; } xpinfo = nlmsg_data (n); if (nla_parse (tb, XFRMA_MAX, nlmsg_attrdata (n, sizeof (struct xfrm_userpolicy_info)), nlmsg_attrlen (n, sizeof (struct xfrm_userpolicy_info)), NULL) < 0) { g_warning ("failed to parse attributes"); return NL_SKIP; } if (tb[XFRMA_TMPL]) { int attrlen = nla_len (tb[XFRMA_TMPL]); struct xfrm_user_tmpl *list = nla_data (tb[XFRMA_TMPL]); int i; xfrm_selector_print (&xpinfo->sel); for (i = 0; i < attrlen / sizeof (struct xfrm_user_tmpl); i++) { struct xfrm_user_tmpl *tmpl = &list[i]; char buf[INET6_ADDRSTRLEN]; g_print (" tmpl "); inet_ntop (tmpl->family, (gpointer) &tmpl->saddr, buf, sizeof (buf)); g_print ("src %s ", buf); inet_ntop (tmpl->family, &tmpl->id.daddr, buf, sizeof (buf)); g_print ("dst %s\n", buf); } } return NL_OK; }
static int tipc_nl_compat_recv(struct sk_buff *skb, struct genl_info *info) { int err; int len; struct tipc_nl_compat_msg msg; struct nlmsghdr *req_nlh; struct nlmsghdr *rep_nlh; struct tipc_genlmsghdr *req_userhdr = info->userhdr; struct net *net = genl_info_net(info); memset(&msg, 0, sizeof(msg)); req_nlh = (struct nlmsghdr *)skb->data; msg.req = nlmsg_data(req_nlh) + GENL_HDRLEN + TIPC_GENL_HDRLEN; msg.cmd = req_userhdr->cmd; msg.dst_sk = info->dst_sk; if ((msg.cmd & 0xC000) && (!netlink_net_capable(skb, CAP_NET_ADMIN))) { msg.rep = tipc_get_err_tlv(TIPC_CFG_NOT_NET_ADMIN); err = -EACCES; goto send; } len = nlmsg_attrlen(req_nlh, GENL_HDRLEN + TIPC_GENL_HDRLEN); if (TLV_GET_LEN(msg.req) && !TLV_OK(msg.req, len)) { msg.rep = tipc_get_err_tlv(TIPC_CFG_NOT_SUPPORTED); err = -EOPNOTSUPP; goto send; } err = tipc_nl_compat_handle(&msg); if (err == -EOPNOTSUPP) msg.rep = tipc_get_err_tlv(TIPC_CFG_NOT_SUPPORTED); else if (err == -EINVAL) msg.rep = tipc_get_err_tlv(TIPC_CFG_TLV_ERROR); send: if (!msg.rep) return err; len = nlmsg_total_size(GENL_HDRLEN + TIPC_GENL_HDRLEN); skb_push(msg.rep, len); rep_nlh = nlmsg_hdr(msg.rep); memcpy(rep_nlh, info->nlhdr, len); rep_nlh->nlmsg_len = msg.rep->len; genlmsg_unicast(net, msg.rep, NETLINK_CB(skb).portid); return err; }
void process_neigh_msg(struct nlmsghdr *nlmsg, int type) { int hdrlen, attrlen; struct nlattr *attr; struct ndmsg *nbh; switchlink_mac_addr_t mac_addr; bool mac_addr_valid = false; bool ipaddr_valid = false; switchlink_ip_addr_t ipaddr; assert((type == RTM_NEWNEIGH) || (type == RTM_DELNEIGH)); nbh = nlmsg_data(nlmsg); hdrlen = sizeof(struct ndmsg); NL_LOG_DEBUG(("%sneigh: family = %d, ifindex = %d, state = 0x%x, " "flags = 0x%x, type = %d\n", ((type == RTM_NEWNEIGH) ? "new" : "del"), nbh->ndm_family, nbh->ndm_ifindex, nbh->ndm_state, nbh->ndm_flags, nbh->ndm_type)); switchlink_db_interface_info_t ifinfo; if (switchlink_db_interface_get_info(nbh->ndm_ifindex, &ifinfo) != SWITCHLINK_DB_STATUS_SUCCESS) { NL_LOG_DEBUG(("neigh: switchlink_db_interface_get_info failed\n")); return; } if (strncmp(ifinfo.ifname, SWITCHLINK_CPU_INTERFACE_NAME, SWITCHLINK_INTERFACE_NAME_LEN_MAX) == 0) { NL_LOG_DEBUG(("neigh: skipping neighbor on CPU interface\n")); return; } memset(&ipaddr, 0, sizeof(switchlink_ip_addr_t)); attrlen = nlmsg_attrlen(nlmsg, hdrlen); attr = nlmsg_attrdata(nlmsg, hdrlen); while (nla_ok(attr, attrlen)) { int attr_type = nla_type(attr); switch (attr_type) { case NDA_DST: ipaddr_valid = true; ipaddr.family = nbh->ndm_family; if (nbh->ndm_family == AF_INET) { ipaddr.ip.v4addr.s_addr = ntohl(nla_get_u32(attr)); ipaddr.prefix_len = 32; } else { memcpy(&(ipaddr.ip.v6addr), nla_data(attr), nla_len(attr)); ipaddr.prefix_len = 128; } break; case NDA_LLADDR: { uint64_t lladdr; mac_addr_valid = true; lladdr = nla_get_u64(attr); memcpy(mac_addr, &lladdr, 6); break; } default: NL_LOG_DEBUG(("neigh: skipping attr(%d)\n", attr_type)); break; } attr = nla_next(attr, &attrlen); } switchlink_handle_t intf_h = ifinfo.intf_h; switchlink_handle_t bridge_h = 0; if (ifinfo.intf_type == SWITCHLINK_INTF_TYPE_L2_ACCESS) { bridge_h = ifinfo.bridge_h; assert(bridge_h); } if (type == RTM_NEWNEIGH) { if (bridge_h && mac_addr_valid) { mac_create(mac_addr, bridge_h, intf_h); } if (ipaddr_valid) { if (mac_addr_valid) { neigh_create(g_default_vrf_h, &ipaddr, mac_addr, intf_h); } else { // mac address is not valid, remove the neighbor entry neigh_delete(g_default_vrf_h, &ipaddr, intf_h); } } } else { if (bridge_h && mac_addr_valid) { mac_delete(mac_addr, bridge_h); } if (ipaddr_valid) { neigh_delete(g_default_vrf_h, &ipaddr, intf_h); } } }
void process_address_msg(struct nlmsghdr *nlmsg, int type) { int hdrlen, attrlen; struct nlattr *attr; struct ifaddrmsg *addrmsg; bool addr_valid = false; switchlink_ip_addr_t addr; assert((type == RTM_NEWADDR) || (type == RTM_DELADDR)); addrmsg = nlmsg_data(nlmsg); hdrlen = sizeof(struct ifaddrmsg); NL_LOG_DEBUG(("%saddr: family = %d, prefixlen = %d, flags = 0x%x, " "scope = 0x%x ifindex = %d\n", ((type == RTM_NEWADDR) ? "new" : "del"), addrmsg->ifa_family, addrmsg->ifa_prefixlen, addrmsg->ifa_flags, addrmsg->ifa_scope, addrmsg->ifa_index)); if ((addrmsg->ifa_family != AF_INET) && (addrmsg->ifa_family != AF_INET6)) { // an address family that we are not interested in, skip return; } switchlink_db_status_t status; switchlink_intf_type_t intf_type = SWITCHLINK_INTF_TYPE_NONE; switchlink_handle_t intf_h = 0; bool create_l3vi = false; switchlink_db_interface_info_t ifinfo; status = switchlink_db_interface_get_info(addrmsg->ifa_index, &ifinfo); if (status == SWITCHLINK_DB_STATUS_SUCCESS) { intf_type = ifinfo.intf_type; intf_h = ifinfo.intf_h; } else { switchlink_db_bridge_info_t brinfo; status = switchlink_db_bridge_get_info(addrmsg->ifa_index, &brinfo); if (status == SWITCHLINK_DB_STATUS_SUCCESS) { create_l3vi = true; } else { // an interface that we are not interested in, skip return; } } if (strcmp(ifinfo.ifname, SWITCHLINK_CPU_INTERFACE_NAME) == 0) { // address on CPU interface, skip return; } attrlen = nlmsg_attrlen(nlmsg, hdrlen); attr = nlmsg_attrdata(nlmsg, hdrlen); while (nla_ok(attr, attrlen)) { int attr_type = nla_type(attr); switch (attr_type) { case IFA_ADDRESS: addr_valid = true; memset(&addr, 0, sizeof(switchlink_ip_addr_t)); addr.family = addrmsg->ifa_family; addr.prefix_len = addrmsg->ifa_prefixlen; if (addrmsg->ifa_family == AF_INET) { addr.ip.v4addr.s_addr = ntohl(nla_get_u32(attr)); } else { memcpy(&(addr.ip.v6addr), nla_data(attr), nla_len(attr)); } break; default: NL_LOG_DEBUG(("addr: skipping attr(%d)\n", attr_type)); break; } attr = nla_next(attr, &attrlen); } if (type == RTM_NEWADDR) { if ((addrmsg->ifa_family == AF_INET) || ((addrmsg->ifa_family == AF_INET6) && !IN6_IS_ADDR_LINKLOCAL(&(addr.ip.v6addr)))) { if (create_l3vi) { interface_create_l3vi(addrmsg->ifa_index); status = switchlink_db_interface_get_info(addrmsg->ifa_index, &ifinfo); assert(status == SWITCHLINK_DB_STATUS_SUCCESS); intf_h = ifinfo.intf_h; } else { if (intf_type == SWITCHLINK_INTF_TYPE_L2_ACCESS) { interface_change_type(addrmsg->ifa_index, SWITCHLINK_INTF_TYPE_L3); } } } if (addr_valid) { switchlink_ip_addr_t null_gateway; memset(&null_gateway, 0, sizeof(null_gateway)); null_gateway.family = addr.family; // add the subnet route route_create(g_default_vrf_h, &addr, &null_gateway, 0, intf_h); // add the interface route if (addrmsg->ifa_family == AF_INET) { addr.prefix_len = 32; } else { addr.prefix_len = 128; } route_create(g_default_vrf_h, &addr, &null_gateway, 0, intf_h); } } else { if (addr_valid) { // remove the subnet route route_delete(g_default_vrf_h, &addr); // remove the interface route if (addrmsg->ifa_family == AF_INET) { addr.prefix_len = 32; } else { addr.prefix_len = 128; } route_delete(g_default_vrf_h, &addr); } } }
extern "C" bool nl_get_ip_info (int rt_msg_type, struct nlmsghdr *hdr, cps_api_object_t obj) { struct ifaddrmsg *ifmsg = (struct ifaddrmsg *)NLMSG_DATA(hdr); if(hdr->nlmsg_len < NLMSG_LENGTH(sizeof(*ifmsg))) return false; typedef enum { IP_KEY, IFINDEX, PREFIX, ADDRESS, IFNAME } attr_t ; static const std::map<uint32_t, std::map<int,cps_api_attr_id_t>> _ipmap = { {AF_INET, { {IP_KEY, BASE_IP_IPV4_OBJ}, {IFINDEX, BASE_IP_IPV4_IFINDEX}, {PREFIX, BASE_IP_IPV4_ADDRESS_PREFIX_LENGTH}, {ADDRESS, BASE_IP_IPV4_ADDRESS_IP}, {IFNAME, BASE_IP_IPV4_NAME} }}, {AF_INET6, { {IP_KEY, BASE_IP_IPV6_OBJ}, {IFINDEX, BASE_IP_IPV6_IFINDEX}, {PREFIX, BASE_IP_IPV6_ADDRESS_PREFIX_LENGTH}, {ADDRESS, BASE_IP_IPV6_ADDRESS_IP}, {IFNAME, BASE_IP_IPV6_NAME} }} }; cps_api_key_from_attr_with_qual(cps_api_object_key(obj),_ipmap.at(ifmsg->ifa_family).at(IP_KEY), cps_api_qualifier_TARGET); cps_api_set_key_data(obj,_ipmap.at(ifmsg->ifa_family).at(IFINDEX), cps_api_object_ATTR_T_U32, &ifmsg->ifa_index,sizeof(ifmsg->ifa_index)); cps_api_object_attr_add_u32(obj, _ipmap.at(ifmsg->ifa_family).at(IFINDEX), ifmsg->ifa_index); cps_api_object_attr_add_u32(obj, _ipmap.at(ifmsg->ifa_family).at(PREFIX), ifmsg->ifa_prefixlen); int nla_len = nlmsg_attrlen(hdr,sizeof(*ifmsg)); struct nlattr *head = nlmsg_attrdata(hdr, sizeof(struct ifaddrmsg)); struct nlattr *attrs[__IFLA_MAX]; memset(attrs,0,sizeof(attrs)); if (nla_parse(attrs,__IFLA_MAX,head,nla_len)!=0) { EV_LOG_TRACE(ev_log_t_NAS_OS,ev_log_s_WARNING,"IP-NL-PARSE","Failed to parse attributes"); cps_api_object_delete(obj); return false; } if(attrs[IFA_ADDRESS]!=NULL) { rta_add_ip((struct nlattr*)ifmsg, ifmsg->ifa_family, obj, _ipmap.at(ifmsg->ifa_family).at(ADDRESS)); } if(attrs[IFA_LABEL]!=NULL) { rta_add_name(attrs[IFA_LABEL], obj, _ipmap.at(ifmsg->ifa_family).at(IFNAME)); } if (rt_msg_type == RTM_NEWADDR) { cps_api_object_set_type_operation(cps_api_object_key(obj),cps_api_oper_CREATE); } else if (rt_msg_type == RTM_DELADDR) { cps_api_object_set_type_operation(cps_api_object_key(obj),cps_api_oper_DELETE); } else { cps_api_object_set_type_operation(cps_api_object_key(obj),cps_api_oper_SET); } return true; }
//db_route_t bool nl_to_route_info(int rt_msg_type, struct nlmsghdr *hdr, cps_api_object_t obj) { struct rtmsg *rtmsg = (struct rtmsg *)NLMSG_DATA(hdr); char addr_str[INET6_ADDRSTRLEN]; if(hdr->nlmsg_len < NLMSG_LENGTH(sizeof(*rtmsg))) return false; if(rt_msg_type == RTM_NEWROUTE) { cps_api_object_attr_add_u32(obj,cps_api_if_ROUTE_A_MSG_TYPE,ROUTE_ADD); } else if(rt_msg_type == RTM_DELROUTE) { cps_api_object_attr_add_u32(obj,cps_api_if_ROUTE_A_MSG_TYPE,ROUTE_DEL); } else { return false; } cps_api_object_attr_add_u32(obj,cps_api_if_ROUTE_A_PROTOCOL,rtmsg->rtm_protocol); cps_api_object_attr_add_u32(obj,cps_api_if_ROUTE_A_FAMILY,rtmsg->rtm_family); int attr_len = nlmsg_attrlen(hdr,sizeof(*rtmsg)); struct nlattr *head = nlmsg_attrdata(hdr, sizeof(struct rtmsg)); struct nlattr *attrs[__IFLA_MAX]; memset(attrs,0,sizeof(attrs)); if (nla_parse(attrs,__IFLA_MAX,head,attr_len)!=0) { EV_LOG(ERR,ROUTE,0,"NL-ROUTE-PARSE","Failed to parse attributes"); return false; } cps_api_key_init(cps_api_object_key(obj),cps_api_qualifier_TARGET, cps_api_obj_cat_ROUTE,cps_api_route_obj_ROUTE,0 ); if(attrs[RTA_DST]!=NULL) { rta_add_ip((struct nlattr*)attrs[RTA_DST],rtmsg->rtm_family, obj,cps_api_if_ROUTE_A_PREFIX); } if((rtmsg->rtm_flags & RTM_F_CLONED) && (rtmsg->rtm_family == AF_INET6)) { // Skip cloned route updates char addr_str[INET6_ADDRSTRLEN]; EV_LOG(INFO, NETLINK,3,"ROUTE-EVENT","Cache entry %s", (attrs[RTA_DST]!=NULL)?(inet_ntop(rtmsg->rtm_family, ((struct in6_addr *) nla_data((struct nlattr*)attrs[RTA_DST])), addr_str, INET6_ADDRSTRLEN)):""); return false; } cps_api_object_attr_add_u32(obj,cps_api_if_ROUTE_A_PREFIX_LEN,rtmsg->rtm_dst_len); size_t hop_count = 0; cps_api_attr_id_t ids[3]; const int ids_len = sizeof(ids)/sizeof(*ids); ids[0] = cps_api_if_ROUTE_A_NH; ids[1] = hop_count; if (attrs[RTA_GATEWAY]!=NULL) { ids[2] = cps_api_if_ROUTE_A_NEXT_HOP_ADDR; rta_add_e_ip((struct nlattr*)attrs[RTA_GATEWAY], rtmsg->rtm_family,obj, ids,ids_len); rta_add_ip((struct nlattr*)attrs[RTA_GATEWAY],rtmsg->rtm_family,obj, cps_api_if_ROUTE_A_NEXT_HOP_ADDR); } if (attrs[RTA_OIF]!=NULL) { ids[2] = cps_api_if_ROUTE_A_NH_IFINDEX; unsigned int *x = (unsigned int *) nla_data(attrs[RTA_OIF]); cps_api_object_e_add(obj,ids,ids_len,cps_api_object_ATTR_T_U32, nla_data(attrs[RTA_OIF]),sizeof(uint32_t)); cps_api_object_attr_add_u32(obj,cps_api_if_ROUTE_A_NH_IFINDEX,*x); } nas_os_log_route_info(rt_msg_type, rtmsg, attrs); if (attrs[RTA_MULTIPATH]) { //array of next hops struct rtnexthop * rtnh = (struct rtnexthop * )nla_data(attrs[RTA_MULTIPATH]); int remaining = nla_len(attrs[RTA_MULTIPATH]); while (RTNH_OK(rtnh, remaining)) { ids[1] = hop_count; ids[2] = cps_api_if_ROUTE_A_NH_IFINDEX; uint32_t _int = rtnh->rtnh_ifindex; cps_api_object_e_add(obj,ids,ids_len,cps_api_object_ATTR_T_U32, &rtnh->rtnh_ifindex,sizeof(uint32_t)); _int = rtnh->rtnh_flags; ids[2] = cps_api_if_ROUTE_A_NEXT_HOP_FLAGS; cps_api_object_e_add(obj,ids,ids_len,cps_api_object_ATTR_T_U32, &_int,sizeof(uint32_t)); ids[2] = cps_api_if_ROUTE_A_NEXT_HOP_WEIGHT; _int = rtnh->rtnh_hops; cps_api_object_e_add(obj,ids,ids_len,cps_api_object_ATTR_T_U32, &_int,sizeof(uint32_t)); struct nlattr *nhattr[__RTA_MAX]; memset(nhattr,0,sizeof(nhattr)); nhrt_parse(nhattr,__IFLA_MAX,rtnh); if (nhattr[RTA_GATEWAY]) { ids[2] = cps_api_if_ROUTE_A_NEXT_HOP_ADDR; rta_add_e_ip((struct nlattr*)nhattr[RTA_GATEWAY], rtmsg->rtm_family,obj, ids,ids_len); EV_LOG(INFO, NETLINK,3,"ROUTE-EVENT","MultiPath nh-cnt:%d gateway:%s ifIndex:%d nh-flags:0x%x weight:%d", hop_count, ((rtmsg->rtm_family == AF_INET) ? (inet_ntop(rtmsg->rtm_family, ((struct in_addr *) nla_data((struct nlattr*)nhattr[RTA_GATEWAY])), addr_str, INET_ADDRSTRLEN)) : (inet_ntop(rtmsg->rtm_family, ((struct in6_addr *) nla_data((struct nlattr*)nhattr[RTA_GATEWAY])), addr_str, INET6_ADDRSTRLEN))), rtnh->rtnh_ifindex, rtnh->rtnh_flags, rtnh->rtnh_hops); } else { EV_LOG(INFO, NETLINK,3,"ROUTE-EVENT","MultiPath nh-cnt:%d ifIndex:%d nh-flags:0x%x weight:%d", hop_count, rtnh->rtnh_ifindex, rtnh->rtnh_flags, rtnh->rtnh_hops); } rtnh = rtnh_next(rtnh,&remaining); ++hop_count; } } else { ++hop_count; } cps_api_object_attr_add_u32(obj,cps_api_if_ROUTE_A_HOP_COUNT,hop_count); return true; }
void process_route_msg(struct nlmsghdr *nlmsg, int type) { int hdrlen, attrlen; struct nlattr *attr; struct rtmsg *rmsg; bool src_valid = false; bool dst_valid = false; bool gateway_valid = false; switchlink_handle_t ecmp_h = 0; switchlink_ip_addr_t src_addr; switchlink_ip_addr_t dst_addr; switchlink_ip_addr_t gateway_addr; switchlink_db_interface_info_t ifinfo; uint8_t af = AF_UNSPEC; bool oif_valid = false; uint32_t oif = 0; switchlink_handle_t oifl_h = 0; bool ip_multicast = false; bool iif_valid = false; uint32_t iif = 0; assert((type == RTM_NEWROUTE) || (type == RTM_DELROUTE)); rmsg = nlmsg_data(nlmsg); hdrlen = sizeof(struct rtmsg); NL_LOG_DEBUG(("%sroute: family = %d, dst_len = %d, src_len = %d, tos = %d, " "table = %d, proto = %d, scope = %d, type = %d, " "flags = 0x%x\n", ((type == RTM_NEWROUTE) ? "new" : "del"), rmsg->rtm_family, rmsg->rtm_dst_len, rmsg->rtm_src_len, rmsg->rtm_tos, rmsg->rtm_table, rmsg->rtm_protocol, rmsg->rtm_scope, rmsg->rtm_type, rmsg->rtm_flags)); if (rmsg->rtm_family > AF_MAX) { assert(rmsg->rtm_type == RTN_MULTICAST); if (rmsg->rtm_family == RTNL_FAMILY_IPMR) { af = AF_INET; } else if (rmsg->rtm_family == RTNL_FAMILY_IP6MR) { af = AF_INET6; } ip_multicast = true; } else { af = rmsg->rtm_family; } if ((af != AF_INET) && (af != AF_INET6)) { return; } memset(&dst_addr, 0, sizeof(switchlink_ip_addr_t)); memset(&gateway_addr, 0, sizeof(switchlink_ip_addr_t)); attrlen = nlmsg_attrlen(nlmsg, hdrlen); attr = nlmsg_attrdata(nlmsg, hdrlen); while (nla_ok(attr, attrlen)) { int attr_type = nla_type(attr); switch (attr_type) { case RTA_SRC: src_valid = true; memset(&src_addr, 0, sizeof(switchlink_ip_addr_t)); src_addr.family = af; src_addr.prefix_len = rmsg->rtm_src_len; if (src_addr.family == AF_INET) { src_addr.ip.v4addr.s_addr = ntohl(nla_get_u32(attr)); } else { memcpy(&(src_addr.ip.v6addr), nla_data(attr), nla_len(attr)); } break; case RTA_DST: dst_valid = true; memset(&dst_addr, 0, sizeof(switchlink_ip_addr_t)); dst_addr.family = af; dst_addr.prefix_len = rmsg->rtm_dst_len; if (dst_addr.family == AF_INET) { dst_addr.ip.v4addr.s_addr = ntohl(nla_get_u32(attr)); } else { memcpy(&(dst_addr.ip.v6addr), nla_data(attr), nla_len(attr)); } break; case RTA_GATEWAY: gateway_valid = true; memset(&gateway_addr, 0, sizeof(switchlink_ip_addr_t)); gateway_addr.family = rmsg->rtm_family; if (rmsg->rtm_family == AF_INET) { gateway_addr.ip.v4addr.s_addr = ntohl(nla_get_u32(attr)); gateway_addr.prefix_len = 32; } else { memcpy(&(gateway_addr.ip.v6addr), nla_data(attr), nla_len(attr)); gateway_addr.prefix_len = 128; } break; case RTA_MULTIPATH: if (ip_multicast) { oifl_h = process_oif_list(attr, g_default_vrf_h); } else { ecmp_h = process_ecmp(af, attr, g_default_vrf_h); } break; case RTA_OIF: oif_valid = true; oif = nla_get_u32(attr); break; case RTA_IIF: iif_valid = true; iif = nla_get_u32(attr); break; default: NL_LOG_DEBUG(("route: skipping attr(%d)\n", attr_type)); break; } attr = nla_next(attr, &attrlen); } if (rmsg->rtm_dst_len == 0) { dst_valid = true; memset(&dst_addr, 0, sizeof(switchlink_ip_addr_t)); dst_addr.family = af; dst_addr.prefix_len = 0; } if (!ip_multicast) { if (type == RTM_NEWROUTE) { memset(&ifinfo, 0, sizeof(ifinfo)); if (oif_valid) { switchlink_db_status_t status; status = switchlink_db_interface_get_info(oif, &ifinfo); if (status != SWITCHLINK_DB_STATUS_SUCCESS) { NL_LOG_DEBUG(("route: switchlink_db_interface_get_info " "(unicast) failed\n")); return; } } route_create(g_default_vrf_h, (dst_valid ? &dst_addr : NULL), (gateway_valid ? &gateway_addr : NULL), ecmp_h, ifinfo.intf_h); } else { route_delete(g_default_vrf_h, (dst_valid ? &dst_addr : NULL)); } } else { if (rmsg->rtm_src_len == 0) { src_valid = true; memset(&src_addr, 0, sizeof(switchlink_ip_addr_t)); src_addr.family = af; src_addr.prefix_len = 0; } if (type == RTM_NEWROUTE) { if (!iif_valid || !oifl_h) { // multicast route cache is not resolved yet return; } switchlink_db_status_t status; status = switchlink_db_interface_get_info(iif, &ifinfo); if (status != SWITCHLINK_DB_STATUS_SUCCESS) { NL_LOG_DEBUG(("route: switchlink_db_interface_get_info " "(multicast) failed\n")); return; } mroute_create(g_default_vrf_h, (src_valid ? &src_addr : NULL), (dst_valid ? &dst_addr : NULL), ifinfo.intf_h, oifl_h); } else { mroute_delete(g_default_vrf_h, (src_valid ? &src_addr : NULL), (dst_valid ? &dst_addr : NULL)); } } }
//db_if_event_t bool nl_get_if_info (int rt_msg_type, struct nlmsghdr *hdr, cps_api_object_t obj) { struct ifinfomsg *ifmsg = (struct ifinfomsg *)NLMSG_DATA(hdr); if(hdr->nlmsg_len < NLMSG_LENGTH(sizeof(*ifmsg))) return false; db_if_type_t _type = DB_IF_TYPE_PHYS_INTER; uint_t ifindex = ifmsg->ifi_index; uint32_t op = 0; EV_LOG(INFO, NAS_OS, 3, "NET-MAIN", "nl_get_if_info msgType %d, ifindex %d change %x\n", rt_msg_type, ifindex, ifmsg->ifi_change); if (rt_msg_type ==RTM_NEWLINK) { op = DB_INTERFACE_OP_CREATE; } else if (rt_msg_type ==RTM_DELLINK) { op = DB_INTERFACE_OP_DELETE; } else { op = DB_INTERFACE_OP_SET; } cps_api_object_attr_add_u32(obj,cps_api_if_STRUCT_A_OPERATION,op); cps_api_object_attr_add_u32(obj,cps_api_if_STRUCT_A_FLAGS, ifmsg->ifi_flags); cps_api_object_attr_add_u32(obj,cps_api_if_STRUCT_A_IFINDEX,ifindex); if(ifmsg->ifi_flags & IFF_UP) { cps_api_object_attr_add_u32(obj,cps_api_if_STRUCT_A_ADMIN_STATE,DB_ADMIN_STATE_UP); } else { cps_api_object_attr_add_u32(obj,cps_api_if_STRUCT_A_ADMIN_STATE,DB_ADMIN_STATE_DN); } int nla_len = nlmsg_attrlen(hdr,sizeof(*ifmsg)); struct nlattr *head = nlmsg_attrdata(hdr, sizeof(struct ifinfomsg)); struct nlattr *attrs[__IFLA_MAX]; memset(attrs,0,sizeof(attrs)); if (nla_parse(attrs,__IFLA_MAX,head,nla_len)!=0) { EV_LOG(ERR,NAS_OS,0,"NL-PARSE","Failed to parse attributes"); cps_api_object_delete(obj); return false; } if (attrs[IFLA_ADDRESS]!=NULL) { rta_add_mac(attrs[IFLA_ADDRESS],obj,cps_api_if_STRUCT_A_IF_MACADDR); } if(attrs[IFLA_IFNAME]!=NULL) { rta_add_name(attrs[IFLA_IFNAME],obj,cps_api_if_STRUCT_A_NAME); } if(attrs[IFLA_MTU]!=NULL) { int *mtu = (int *) nla_data(attrs[IFLA_MTU]); cps_api_object_attr_add_u32(obj,cps_api_if_STRUCT_A_MTU,(*mtu + NAS_LINK_MTU_HDR_SIZE)); } if(attrs[IFLA_MASTER]!=NULL) { /* This gives us the bridge index, which should be sent to * NAS for correlation */ EV_LOG(INFO, NAS_OS, 3, "NET-MAIN", "Rcvd master index %d", *(int *)nla_data(attrs[IFLA_MASTER])); cps_api_object_attr_add_u32(obj,cps_api_if_STRUCT_A_MASTER, *(int *)nla_data(attrs[IFLA_MASTER])); if(op == DB_INTERFACE_OP_DELETE) { /* With Dell offering VLAN data structures use port index instead of * vlan interface */ int phy_ifindex = 0; nas_os_physical_to_vlan_ifindex(ifindex, 0, false, &phy_ifindex); cps_api_object_attr_add_u32(obj,cps_api_if_STRUCT_A_IFINDEX, phy_ifindex); cps_api_object_attr_add_u32(obj, cps_api_if_STRUCT_A_VLAN_PORT_INDEX, ifindex); _type = DB_IF_TYPE_VLAN_INTER; } } struct nlattr *linkinfo[IFLA_INFO_MAX]; struct nlattr *vlan[IFLA_VLAN_MAX]; char *info_kind; if (attrs[IFLA_LINKINFO]) { memset(linkinfo,0,sizeof(linkinfo)); nla_parse_nested(linkinfo,IFLA_INFO_MAX,attrs[IFLA_LINKINFO]); if(linkinfo[IFLA_INFO_KIND]) { info_kind = (char *)nla_data(linkinfo[IFLA_INFO_KIND]); EV_LOG(INFO, NAS_OS, 3, "NET-MAIN", "In IFLA_INFO_KIND for %s index %d", info_kind, ifindex); if(!strncmp(info_kind, "vlan", 4)) { if(attrs[IFLA_MASTER]!=NULL) { if (linkinfo[IFLA_INFO_DATA]) { memset(vlan,0,sizeof(vlan)); nla_parse_nested(vlan,IFLA_VLAN_MAX,linkinfo[IFLA_INFO_DATA]); if (vlan[IFLA_VLAN_ID]) { EV_LOG(INFO, NAS_OS, 3, "NET-MAIN", "Received VLAN %d", ifindex); cps_api_object_attr_add_u32(obj,cps_api_if_STRUCT_A_VLAN_ID, *(uint16_t*)nla_data(vlan[IFLA_VLAN_ID])); _type = DB_IF_TYPE_VLAN_INTER; if (attrs[IFLA_LINK]) { //port that is added to vlan uint32_t portIndex = *(uint32_t*)nla_data(attrs[IFLA_LINK]); if (op == DB_INTERFACE_OP_DELETE) { cps_api_object_attr_add_u32(obj, cps_api_if_STRUCT_A_VLAN_PORT_INDEX, ifindex); } else { cps_api_object_attr_add_u32(obj, cps_api_if_STRUCT_A_VLAN_PORT_INDEX, portIndex); } } //IFLA_LINK } //IFLA_VLAN_ID }//IFLA_INFO_DATA }// IFLA_MASTER } // vlan interface else if(!strncmp(info_kind, "tun", 3)) { /* TODO : Revisit this and introduce a logical interface type */ if(attrs[IFLA_MASTER]!=NULL) { EV_LOG(INFO, NAS_OS,3, "NET-MAIN", "Received tun %d", ifindex); _type = DB_IF_TYPE_VLAN_INTER; cps_api_object_attr_add_u32(obj, cps_api_if_STRUCT_A_VLAN_PORT_INDEX, ifindex); } if(ifmsg->ifi_flags & IFF_SLAVE) { EV_LOG(INFO, NAS_OS,3, "NET-MAIN", "Received tun %d and state IFF_UP", ifindex,ifmsg->ifi_flags); _type = DB_IF_TYPE_LAG_INTER; } } else if(!strncmp(info_kind, "bridge", 6)) { EV_LOG(INFO,NAS_OS,3, "NET-MAIN", "Bridge intf index is %d ", ifindex); _type = DB_IF_TYPE_BRIDGE_INTER; } /* bridge interface */ else if(!strncmp(info_kind, "bond", 4)) { EV_LOG(INFO, NAS_OS,3, "NET-MAIN", "Bond interface index is %d ", ifindex); _type = DB_IF_TYPE_LAG_INTER; if(attrs[IFLA_MASTER]!=NULL) { EV_LOG(INFO, NAS_OS,3, "NET-MAIN", "Received bond %d with master set %d", ifindex, *(int *)nla_data(attrs[IFLA_MASTER])); /* Bond with master set, means configured in a bridge * Pass the master index as the ifindex for vlan processing to continue */ _type = DB_IF_TYPE_VLAN_INTER; cps_api_object_attr_add_u32(obj, cps_api_if_STRUCT_A_VLAN_PORT_INDEX, ifindex); if (op == DB_INTERFACE_OP_DELETE ) { cps_api_object_attr_add_u32(obj,cps_api_if_STRUCT_A_IFINDEX, *(int *)nla_data(attrs[IFLA_MASTER])); } } } // bond interface } } if(attrs[IFLA_OPERSTATE]!=NULL) { int *link = (int *) nla_data(attrs[IFLA_OPERSTATE]); if (*link==IF_OPER_UP) { cps_api_object_attr_add_u32(obj,cps_api_if_STRUCT_A_OPER_STATE,DB_OPER_STATE_UP); } else if (*link==IF_OPER_DOWN) { cps_api_object_attr_add_u32(obj,cps_api_if_STRUCT_A_OPER_STATE,DB_OPER_STATE_DN); } } cps_api_object_attr_add_u32(obj,cps_api_if_STRUCT_A_IF_TYPE,_type); cps_api_int_if_key_create(cps_api_object_key(obj),true,0,ifindex); return true; }