コード例 #1
0
ファイル: neigh.c プロジェクト: ebichu/dd-wrt
static struct nl_msg * build_neigh_msg(struct rtnl_neigh *tmpl, int cmd,
				       int flags)
{
	struct nl_msg *m;
	struct nlmsghdr n = {
		.nlmsg_type = cmd,
		.nlmsg_flags = flags,
	};
	struct ndmsg nm = {
		.ndm_ifindex = tmpl->n_ifindex,
		.ndm_family = tmpl->n_dst.a_family,
		.ndm_state = tmpl->n_state,
	};

	m = nl_msg_build(&n);
	nl_msg_append_raw(m, &nm, sizeof(nm));
	nl_msg_append_tlv(m, NDA_DST, &tmpl->n_dst.a_addr, tmpl->n_dst.a_len);

	if (tmpl->n_mask & NEIGH_HAS_LLADDR)
		nl_msg_append_tlv(m, NDA_LLADDR, &tmpl->n_lladdr.a_addr,
		    tmpl->n_lladdr.a_len);

	return m;
}

/**
 * Build netlink request message to add a new neighbour
 * @arg tmpl		template with data of new neighbour
 *
 * Builds a new netlink message requesting a addition of a new
 * neighbour. The netlink message header isn't fully equipped with
 * all relevant fields and must thus be sent out via nl_send_auto_complete()
 * or supplemented as needed. \a tmpl must contain the attributes of the new
 * neighbour set via \c rtnl_neigh_set_* functions.
 * 
 * The following attributes must be set in the template:
 *  - Interface index (rtnl_neigh_set_ifindex())
 *  - State (rtnl_neigh_set_state())
 *  - Destination address (rtnl_neigh_set_dst())
 *  - Link layer address (rtnl_neigh_set_lladdr())
 *
 * @return The netlink message
 */
struct nl_msg * rtnl_neigh_build_add_request(struct rtnl_neigh *tmpl)
{
	return build_neigh_msg(tmpl, RTM_NEWNEIGH, NLM_F_CREATE);
}

/**
 * Add a new neighbour
 * @arg handle		netlink handle
 * @arg tmpl		template with requested changes
 *
 * Builds a netlink message by calling rtnl_neigh_build_add_request(),
 * sends the request to the kernel and waits for the next ACK to be
 * received and thus blocks until the request has been fullfilled.
 *
 * The following attributes must be set in the template:
 *  - Interface index (rtnl_neigh_set_ifindex())
 *  - State (rtnl_neigh_set_state())
 *  - Destination address (rtnl_neigh_set_dst())
 *  - Link layer address (rtnl_neigh_set_lladdr())
 *
 * @return 0 on sucess or a negative error if an error occured.
 */
int rtnl_neigh_add(struct nl_handle *handle, struct rtnl_neigh *tmpl)
{
	int err;
	struct nl_msg *m = rtnl_neigh_build_add_request(tmpl);

	if ((err = nl_send_auto_complete(handle, nl_msg_get(m))) < 0)
		return err;

	nl_msg_free(m);
	return nl_wait_for_ack(handle);
}
コード例 #2
0
ファイル: nl_bridge.cpp プロジェクト: toanju/basebox
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;
}