Пример #1
0
/**
 * Set link layer address of a neighbour
 * @arg neigh		neighbour to change
 * @arg addr		new link layer address as string
 *
 * Translates the specified address to a binary format and assigns it
 * as the new link layer address by calling rtnl_neigh_set_lladdr().
 *
 * @see rtnl_neigh_set_lladdr()
 * @return 0 on success or a negative error code.
 */
int rtnl_neigh_set_lladdr_str(struct rtnl_neigh *neigh, const char *addr)
{
	int err;
	struct nl_addr a = {0};
	
	err = nl_str2addr(addr, &a, AF_UNSPEC);
	if (err < 0)
		return err;

	rtnl_neigh_set_lladdr(neigh, &a);
	return 0;
}
Пример #2
0
void
switchlink_linux_mac_update(switchlink_mac_addr_t mac_addr,
                            switchlink_handle_t bridge_h,
                            switchlink_handle_t intf_h, bool create) {
    switchlink_db_status_t status;
    uint32_t ifindex;

    if (!create) {
        status = switchlink_db_mac_get_intf(mac_addr, bridge_h, &intf_h);
        if (status != SWITCHLINK_DB_STATUS_SUCCESS) {
            assert(false);
            return;
        }
    }

    status = switchlink_db_interface_get_ifindex(intf_h, &ifindex);
    if (status != SWITCHLINK_DB_STATUS_SUCCESS) {
        assert(false);
        return;
    }

    struct nl_sock *nlsk = switchlink_get_nl_sock();
    if (!nlsk) {
        return;
    }

    struct nl_addr *nl_addr = nl_addr_build(AF_LLC, mac_addr, ETH_ALEN);
    struct rtnl_neigh *rtnl_neigh = rtnl_neigh_alloc();
    rtnl_neigh_set_ifindex(rtnl_neigh, ifindex);
    rtnl_neigh_set_lladdr(rtnl_neigh, nl_addr);
    rtnl_neigh_set_state(rtnl_neigh, rtnl_neigh_str2state("permanent"));
    rtnl_neigh_set_family(rtnl_neigh, AF_BRIDGE);

    if (create) {
        status = switchlink_db_mac_add(mac_addr, bridge_h, intf_h);
        assert(status == SWITCHLINK_DB_STATUS_SUCCESS);
        rtnl_neigh_add(nlsk, rtnl_neigh, NLM_F_CREATE|NLM_F_REPLACE);
    } else {
        status = switchlink_db_mac_delete(mac_addr, bridge_h);
        assert(status == SWITCHLINK_DB_STATUS_SUCCESS);
        rtnl_neigh_delete(nlsk, rtnl_neigh, 0);
    }
    rtnl_neigh_put(rtnl_neigh);
    nl_addr_put(nl_addr);
}
Пример #3
0
int nl_bridge::fdb_timeout(rtnl_link *br_link, uint16_t vid,
                           const rofl::caddress_ll &mac) {
  int rv = 0;

  std::unique_ptr<rtnl_neigh, decltype(&rtnl_neigh_put)> n(rtnl_neigh_alloc(),
                                                           rtnl_neigh_put);

  std::unique_ptr<nl_addr, decltype(&nl_addr_put)> h_src(
      nl_addr_build(AF_LLC, mac.somem(), mac.memlen()), nl_addr_put);

  rtnl_neigh_set_ifindex(n.get(), rtnl_link_get_ifindex(br_link));
  rtnl_neigh_set_master(n.get(), rtnl_link_get_master(br_link));
  rtnl_neigh_set_family(n.get(), AF_BRIDGE);
  rtnl_neigh_set_vlan(n.get(), vid);
  rtnl_neigh_set_lladdr(n.get(), h_src.get());
  rtnl_neigh_set_flags(n.get(), NTF_MASTER | NTF_EXT_LEARNED);
  rtnl_neigh_set_state(n.get(), NUD_REACHABLE);

  // find entry in local l2_cache
  std::unique_ptr<rtnl_neigh, decltype(&rtnl_neigh_put)> n_lookup(
      NEIGH_CAST(nl_cache_search(l2_cache.get(), OBJ_CAST(n.get()))),
      rtnl_neigh_put);

  if (n_lookup) {
    // * remove l2 entry from kernel
    nl_msg *msg = nullptr;
    rtnl_neigh_build_delete_request(n.get(), NLM_F_REQUEST, &msg);
    assert(msg);

    // send the message and create new fdb entry
    if (nl->send_nl_msg(msg) < 0) {
      LOG(ERROR) << __FUNCTION__ << ": failed to send netlink message";
      return -EINVAL;
    }

    // XXX TODO maybe delete after NL event and not yet here
    nl_cache_remove(OBJ_CAST(n_lookup.get()));
  }

  return rv;
}
Пример #4
0
int nl_bridge::learn_source_mac(rtnl_link *br_link, packet *p) {
  // we still assume vlan filtering bridge
  assert(rtnl_link_get_family(br_link) == AF_BRIDGE);

  VLOG(2) << __FUNCTION__ << ": pkt " << p << " on link " << OBJ_CAST(br_link);

  rtnl_link_bridge_vlan *br_vlan = rtnl_link_bridge_get_port_vlan(br_link);

  if (br_vlan == nullptr) {
    LOG(ERROR) << __FUNCTION__
               << ": only the vlan filtering bridge is supported";
    return -EINVAL;
  }

  // parse ether frame and check for vid
  vlan_hdr *hdr = reinterpret_cast<basebox::vlan_hdr *>(p->data);
  uint16_t vid = 0;

  // XXX TODO maybe move this to the utils to have a std lib for parsing the
  // ether frame
  switch (ntohs(hdr->eth.h_proto)) {
  case ETH_P_8021Q:
    // vid
    vid = ntohs(hdr->vlan);
    break;
  default:
    // no vid, set vid to pvid
    vid = br_vlan->pvid;
    LOG(WARNING) << __FUNCTION__ << ": assuming untagged for ethertype "
                 << std::showbase << std::hex << ntohs(hdr->eth.h_proto);
    break;
  }

  // verify that the vid is in use here
  if (!is_vid_set(vid, br_vlan->vlan_bitmap)) {
    LOG(WARNING) << __FUNCTION__ << ": got packet on unconfigured port";
    return -ENOTSUP;
  }

  // set nl neighbour to NL
  std::unique_ptr<nl_addr, decltype(&nl_addr_put)> h_src(
      nl_addr_build(AF_LLC, hdr->eth.h_source, sizeof(hdr->eth.h_source)),
      nl_addr_put);

  if (!h_src) {
    LOG(ERROR) << __FUNCTION__ << ": failed to allocate src mac";
    return -ENOMEM;
  }

  std::unique_ptr<rtnl_neigh, decltype(&rtnl_neigh_put)> n(rtnl_neigh_alloc(),
                                                           rtnl_neigh_put);

  rtnl_neigh_set_ifindex(n.get(), rtnl_link_get_ifindex(br_link));
  rtnl_neigh_set_master(n.get(), rtnl_link_get_master(br_link));
  rtnl_neigh_set_family(n.get(), AF_BRIDGE);
  rtnl_neigh_set_vlan(n.get(), vid);
  rtnl_neigh_set_lladdr(n.get(), h_src.get());
  rtnl_neigh_set_flags(n.get(), NTF_MASTER | NTF_EXT_LEARNED);
  rtnl_neigh_set_state(n.get(), NUD_REACHABLE);

  // check if entry already exists in cache
  if (is_mac_in_l2_cache(n.get())) {
    return 0;
  }

  nl_msg *msg = nullptr;
  rtnl_neigh_build_add_request(n.get(),
                               NLM_F_REQUEST | NLM_F_CREATE | NLM_F_EXCL, &msg);
  assert(msg);

  // send the message and create new fdb entry
  if (nl->send_nl_msg(msg) < 0) {
    LOG(ERROR) << __FUNCTION__ << ": failed to send netlink message";
    return -EINVAL;
  }

  // cache the entry
  if (nl_cache_add(l2_cache.get(), OBJ_CAST(n.get())) < 0) {
    LOG(ERROR) << __FUNCTION__ << ": failed to add entry to l2_cache "
               << OBJ_CAST(n.get());
    return -EINVAL;
  }

  VLOG(2) << __FUNCTION__ << ": learned new source mac " << OBJ_CAST(n.get());

  return 0;
}