示例#1
0
void neigh_create(switchlink_handle_t vrf_h,
                  switchlink_ip_addr_t *ipaddr,
                  switchlink_mac_addr_t mac_addr,
                  switchlink_handle_t intf_h) {
  switchlink_db_status_t status;
  switchlink_db_neigh_info_t neigh_info;

  if ((ipaddr->family == AF_INET6) &&
      IN6_IS_ADDR_MULTICAST(&(ipaddr->ip.v6addr))) {
    return;
  }

  memset(&neigh_info, 0, sizeof(switchlink_db_neigh_info_t));
  neigh_info.vrf_h = vrf_h;
  neigh_info.intf_h = intf_h;
  memcpy(&(neigh_info.ip_addr), ipaddr, sizeof(switchlink_ip_addr_t));

  status = switchlink_db_neighbor_get_info(&neigh_info);
  if (status == SWITCHLINK_DB_STATUS_SUCCESS) {
    if (memcmp(neigh_info.mac_addr, mac_addr, sizeof(switchlink_mac_addr_t)) ==
        0) {
      // no change
      return;
    }

    // update, currently handled as a delete followed by add
    neigh_delete(vrf_h, ipaddr, intf_h);
  }

  memcpy(neigh_info.mac_addr, mac_addr, sizeof(switchlink_mac_addr_t));
  if (switchlink_nexthop_create(&neigh_info) == -1) {
    return;
  }
  if (switchlink_neighbor_create(&neigh_info) == -1) {
    switchlink_nexthop_delete(&neigh_info);
    return;
  }
  switchlink_db_neighbor_add(&neigh_info);

  // add a host route
  route_create(g_default_vrf_h, ipaddr, ipaddr, 0, intf_h);
}
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);
        }
    }
}
示例#3
0
文件: netlink.c 项目: edenden/ufp
static void netlink_neigh(struct ufpd_thread *thread, struct nlmsghdr *nlh)
{
	struct ndmsg *neigh_entry;
	struct rtattr *route_attr;
	struct neigh_table *neigh;
	int route_attr_len;
	int ifindex;
	int family;
	uint8_t dst_addr[16] = {};
	uint8_t dst_mac[ETH_ALEN] = {};
	int i, port_index = -1;

	neigh_entry = (struct ndmsg *)NLMSG_DATA(nlh);
	family		= neigh_entry->ndm_family;
	ifindex		= neigh_entry->ndm_ifindex;
	port_index 	= -1;

	for(i = 0; i < thread->num_ports; i++){
		if(ufp_tun_index(thread->plane, i) == ifindex){
			port_index = i;
			break;
		}
	}

	if(port_index < 0)
		goto out;

	route_attr = (struct rtattr *)RTM_RTA(neigh_entry);
	route_attr_len = RTM_PAYLOAD(nlh);

	while(RTA_OK(route_attr, route_attr_len)){
		switch(route_attr->rta_type){
		case NDA_DST:
			memcpy(dst_addr, RTA_DATA(route_attr),
				RTA_PAYLOAD(route_attr));
			break;
		case NDA_LLADDR:
			memcpy(dst_mac, RTA_DATA(route_attr),
				RTA_PAYLOAD(route_attr));
			break;
		default:
			break;
		}

		route_attr = RTA_NEXT(route_attr, route_attr_len);
	}

	switch(family){
	case AF_INET:
		neigh = thread->neigh_inet[port_index];
		break;
	case AF_INET6:
		neigh = thread->neigh_inet6[port_index];
		break;
	default:
		goto out;
		break;
	}

	switch(nlh->nlmsg_type){
	case RTM_NEWNEIGH:
		neigh_add(neigh, family, dst_addr, dst_mac,
			thread->mpool);
		break;
	case RTM_DELNEIGH:
		neigh_delete(neigh, family, dst_addr);
		break;
	default:
		break;
	}

out:
	return;
}