예제 #1
0
static void
mac_create(switchlink_mac_addr_t mac_addr, switchlink_handle_t bridge_h,
           switchlink_handle_t intf_h) {
    switchlink_handle_t old_intf_h;
    switchlink_db_status_t status;
    status = switchlink_db_mac_get_intf(mac_addr, bridge_h, &old_intf_h);
    if (status == SWITCHLINK_DB_STATUS_SUCCESS) {
       if (old_intf_h == intf_h) {
           // no change
           return;
       } else {
           // update handled as delete followed by add
           mac_delete(mac_addr, bridge_h);
       }
    }

    switchlink_mac_create(mac_addr, bridge_h, intf_h);
    switchlink_db_mac_add(mac_addr, bridge_h, intf_h);
}
예제 #2
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);
        }
    }
}