Пример #1
0
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;
}
Пример #2
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;
}
Пример #3
0
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;
}
Пример #4
0
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);
        }
    }
}
Пример #6
0
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;
}
Пример #7
0
//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;
}
Пример #8
0
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));
        }
    }
}
Пример #9
0
//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;
}