static int get_mcast_mac_ipv6(struct nl_addr *dst, struct nl_addr **ll_addr) { uint8_t mac_addr[6] = {0x33, 0x33}; memcpy(mac_addr + 2, (uint8_t *)nl_addr_get_binary_addr(dst) + 12, 4); *ll_addr = nl_addr_build(AF_LLC, mac_addr, sizeof(mac_addr)); return *ll_addr == NULL ? -EINVAL : 0; }
static int get_link_local_mac_ipv6(struct nl_addr *dst, struct nl_addr **ll_addr) { uint8_t mac_addr[6]; memcpy(mac_addr + 3, (uint8_t *)nl_addr_get_binary_addr(dst) + 13, 3); memcpy(mac_addr, (uint8_t *)nl_addr_get_binary_addr(dst) + 8, 3); mac_addr[0] ^= 2; *ll_addr = nl_addr_build(AF_LLC, mac_addr, sizeof(mac_addr)); return *ll_addr == NULL ? -EINVAL : 0; }
static int result_msg_parser(struct nl_cache_ops *ops, struct sockaddr_nl *who, struct nlmsghdr *n, struct nl_parser_param *pp) { struct flnl_result *res; struct fib_result_nl *fr; struct nl_addr *addr; int err = -EINVAL; res = flnl_result_alloc(); if (!res) goto errout; res->ce_msgtype = n->nlmsg_type; res->fr_req = flnl_request_alloc(); if (!res->fr_req) goto errout; fr = nlmsg_data(n); addr = nl_addr_build(AF_INET, &fr->fl_addr, 4); if (!addr) goto errout; err = flnl_request_set_addr(res->fr_req, addr); nl_addr_put(addr); if (err < 0) goto errout; flnl_request_set_fwmark(res->fr_req, fr->fl_fwmark); flnl_request_set_tos(res->fr_req, fr->fl_tos); flnl_request_set_scope(res->fr_req, fr->fl_scope); flnl_request_set_table(res->fr_req, fr->tb_id_in); res->fr_table_id = fr->tb_id; res->fr_prefixlen = fr->prefixlen; res->fr_nh_sel = fr->nh_sel; res->fr_type = fr->type; res->fr_scope = fr->scope; res->fr_error = fr->err; err = pp->pp_cb((struct nl_object *) res, pp); if (err < 0) goto errout; /* REAL HACK, fib_lookup doesn't support ACK nor does it * send a DONE message, enforce end of message stream * after just the first message */ err = NL_STOP; errout: flnl_result_put(res); return err; }
static int get_mcast_mac_ipv4(struct nl_addr *dst, struct nl_addr **ll_addr) { uint8_t mac_addr[6] = {0x01, 0x00, 0x5E}; uint32_t addr = be32toh(*(__be32 *)nl_addr_get_binary_addr(dst)); mac_addr[5] = addr & 0xFF; addr >>= 8; mac_addr[4] = addr & 0xFF; addr >>= 8; mac_addr[3] = addr & 0x7F; *ll_addr = nl_addr_build(AF_LLC, mac_addr, sizeof(mac_addr)); return *ll_addr == NULL ? -EINVAL : 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); }
/** * Get IPv6 tokenized interface identifier * @arg link Link object * @arg token Tokenized interface identifier on success * * Returns the link's IPv6 tokenized interface identifier. * * @return 0 on success * @return -NLE_NOMEM failure to allocate struct nl_addr result * @return -NLE_NOATTR configuration setting not available * @return -NLE_NOADDR tokenized interface identifier is not set */ int rtnl_link_inet6_get_token(struct rtnl_link *link, struct nl_addr **addr) { struct inet6_data *id; if (!(id = rtnl_link_af_data(link, &inet6_ops))) return -NLE_NOATTR; *addr = nl_addr_build(AF_INET6, &id->i6_token, sizeof(id->i6_token)); if (!*addr) return -NLE_NOMEM; if (nl_addr_iszero(*addr)) { nl_addr_put(*addr); *addr = NULL; return -NLE_NOADDR; } return 0; }
int main(int argc, char *argv[]) { struct rtnl_link *link; struct nl_cache *link_cache; struct nl_sock *sk; struct nl_addr* addr; int err, master_index; sk = nl_socket_alloc(); if ((err = nl_connect(sk, NETLINK_ROUTE)) < 0) { nl_perror(err, "Unable to connect socket"); return err; } if ((err = rtnl_link_alloc_cache(sk, AF_UNSPEC, &link_cache)) < 0) { nl_perror(err, "Unable to allocate cache"); return err; } if (!(master_index = rtnl_link_name2i(link_cache, "eth0"))) { fprintf(stderr, "Unable to lookup eth0"); return -1; } link = rtnl_link_macvtap_alloc(); rtnl_link_set_link(link, master_index); addr = nl_addr_build(AF_LLC, ether_aton("00:11:22:33:44:55"), ETH_ALEN); rtnl_link_set_addr(link, addr); nl_addr_put(addr); rtnl_link_macvtap_set_mode(link, rtnl_link_macvtap_str2mode("bridge")); if ((err = rtnl_link_add(sk, link, NLM_F_CREATE)) < 0) { nl_perror(err, "Unable to add link"); return err; } rtnl_link_put(link); nl_close(sk); return 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; }
int sysnet_interface_set_addr(VPNInterface *i) { int err; struct nl_cache *link_cache; struct nl_sock *sock; struct rtnl_addr *addr; struct rtnl_link *link; struct nl_addr *local_addr; sock = nl_socket_alloc(); nl_connect(sock, NETLINK_ROUTE); rtnl_link_alloc_cache(sock, AF_UNSPEC, &link_cache); addr = rtnl_addr_alloc(); link = rtnl_link_get_by_name(link_cache, i->name); local_addr = nl_addr_build(i->address.ip.family, &i->address.ip.ip4, sizeof(i->address.ip.ip4)); rtnl_addr_set_local(addr, local_addr); rtnl_addr_set_family(addr, i->address.ip.family); rtnl_addr_set_prefixlen(addr, i->address.prefix); rtnl_addr_set_link(addr, link); if ((err = rtnl_addr_add(sock, addr, 0)) < 0) { tox_trace(i->context->tox, "Unable to add address %s on %s: %s", ip_ntoa(&i->address.ip), rtnl_link_get_name(link), nl_geterror(err)); } else { tox_trace(i->context->tox, "Added address %s on \"%s\"", ip_ntoa(&i->address.ip), i->name); } rtnl_link_put(link); rtnl_addr_put(addr); nl_cache_free(link_cache); nl_addr_put(local_addr); nl_socket_free(sock); return err; }
int xfrmnl_ae_parse(struct nlmsghdr *n, struct xfrmnl_ae **result) { struct xfrmnl_ae* ae; struct nlattr *tb[XFRMA_MAX + 1]; struct xfrm_aevent_id* ae_id; int err; ae = xfrmnl_ae_alloc(); if (!ae) { err = -NLE_NOMEM; goto errout; } ae->ce_msgtype = n->nlmsg_type; ae_id = nlmsg_data(n); err = nlmsg_parse(n, sizeof(struct xfrm_aevent_id), tb, XFRMA_MAX, xfrm_ae_policy); if (err < 0) goto errout; ae->sa_id.daddr = nl_addr_build(ae_id->sa_id.family, &ae_id->sa_id.daddr, sizeof (ae_id->sa_id.daddr)); ae->sa_id.family= ae_id->sa_id.family; ae->sa_id.spi = ntohl(ae_id->sa_id.spi); ae->sa_id.proto = ae_id->sa_id.proto; ae->saddr = nl_addr_build(ae_id->sa_id.family, &ae_id->saddr, sizeof (ae_id->saddr)); ae->reqid = ae_id->reqid; ae->flags = ae_id->flags; ae->ce_mask |= (XFRM_AE_ATTR_DADDR | XFRM_AE_ATTR_FAMILY | XFRM_AE_ATTR_SPI | XFRM_AE_ATTR_PROTO | XFRM_AE_ATTR_SADDR | XFRM_AE_ATTR_REQID | XFRM_AE_ATTR_FLAGS); if (tb[XFRMA_MARK]) { struct xfrm_mark* m = nla_data(tb[XFRMA_MARK]); ae->mark.m = m->m; ae->mark.v = m->v; ae->ce_mask |= XFRM_AE_ATTR_MARK; } if (tb[XFRMA_LTIME_VAL]) { struct xfrm_lifetime_cur* cur = nla_data(tb[XFRMA_LTIME_VAL]); ae->lifetime_cur.bytes = cur->bytes; ae->lifetime_cur.packets = cur->packets; ae->lifetime_cur.add_time = cur->add_time; ae->lifetime_cur.use_time = cur->use_time; ae->ce_mask |= XFRM_AE_ATTR_LIFETIME; } if (tb[XFRM_AE_ETHR]) { ae->replay_maxage = *(uint32_t*)nla_data(tb[XFRM_AE_ETHR]); ae->ce_mask |= XFRM_AE_ATTR_REPLAY_MAXAGE; } if (tb[XFRM_AE_RTHR]) { ae->replay_maxdiff = *(uint32_t*)nla_data(tb[XFRM_AE_RTHR]); ae->ce_mask |= XFRM_AE_ATTR_REPLAY_MAXDIFF; } if (tb[XFRMA_REPLAY_ESN_VAL]) { struct xfrm_replay_state_esn* esn = nla_data (tb[XFRMA_REPLAY_ESN_VAL]); uint32_t len = sizeof (struct xfrmnl_replay_state_esn) + (sizeof (uint32_t) * esn->bmp_len); if ((ae->replay_state_esn = calloc (1, len)) == NULL) { err = -ENOMEM; goto errout; } ae->replay_state_esn->oseq = esn->oseq; ae->replay_state_esn->seq = esn->seq; ae->replay_state_esn->oseq_hi = esn->oseq_hi; ae->replay_state_esn->seq_hi = esn->seq_hi; ae->replay_state_esn->replay_window = esn->replay_window; ae->replay_state_esn->bmp_len = esn->bmp_len; memcpy (ae->replay_state_esn->bmp, esn->bmp, sizeof (uint32_t) * esn->bmp_len); ae->ce_mask |= XFRM_AE_ATTR_REPLAY_STATE; } else { struct xfrm_replay_state* replay_state = nla_data (tb[XFRMA_REPLAY_VAL]); ae->replay_state.oseq = replay_state->oseq; ae->replay_state.seq = replay_state->seq; ae->replay_state.bitmap = replay_state->bitmap; ae->ce_mask |= XFRM_AE_ATTR_REPLAY_STATE; ae->replay_state_esn = NULL; } *result = ae; return 0; errout: xfrmnl_ae_put(ae); return err; }
/** * _route_add: * @route: the route to add * @family: address family, either %AF_INET or %AF_INET6 * @dest: the route destination address, either a struct in_addr or a struct * in6_addr depending on @family * @dest_prefix: the CIDR prefix of @dest * @gateway: the gateway through which to reach @dest, if any; given as a * struct in_addr or struct in6_addr depending on @family * @flags: flags to pass to rtnl_route_add(), eg %NLM_F_REPLACE * * Returns: zero if succeeded or the netlink error otherwise. **/ static int _route_add (struct rtnl_route *route, int family, const void *dest, /* in_addr or in6_addr */ int dest_prefix, const void *gateway, /* in_addr or in6_addr */ int flags) { struct nl_sock *sk; struct nl_addr *dest_addr, *gw_addr; void *tmp_addr; int addrlen, err, log; if (family == AF_INET) { addrlen = sizeof (struct in_addr); log = LOGD_IP4; } else if (family == AF_INET6) { addrlen = sizeof (struct in6_addr); log = LOGD_IP6; } else g_assert_not_reached (); sk = nm_netlink_get_default_handle (); /* Build up the destination address */ if (dest) { /* Copy to preserve const */ tmp_addr = g_malloc0 (addrlen); memcpy (tmp_addr, dest, addrlen); dest_addr = nl_addr_build (family, tmp_addr, addrlen); g_free (tmp_addr); g_return_val_if_fail (dest_addr != NULL, -NLE_INVAL); nl_addr_set_prefixlen (dest_addr, dest_prefix); rtnl_route_set_dst (route, dest_addr); nl_addr_put (dest_addr); } /* Build up the gateway address */ if (gateway) { tmp_addr = g_malloc0 (addrlen); memcpy (tmp_addr, gateway, addrlen); gw_addr = nl_addr_build (family, tmp_addr, addrlen); g_free (tmp_addr); if (gw_addr) { nl_addr_set_prefixlen (gw_addr, 0); rtnl_route_set_gateway (route, gw_addr); rtnl_route_set_scope (route, RT_SCOPE_UNIVERSE); nl_addr_put (gw_addr); } else nm_log_err (LOGD_DEVICE | log, "Invalid gateway"); } err = rtnl_route_add (sk, route, flags); /* LIBNL Bug: Aliased ESRCH */ if (err == -NLE_FAILURE) err = -NLE_OBJ_NOTFOUND; return err; }
int ip_addr(char *ip4addr, char *interface, cmd_t cmd) { struct nl_handle *nlh = NULL; struct rtnl_addr *addr = NULL; struct nl_addr *nl_addr = NULL; uint32_t binaddr = 0; int iface_idx = -1; int err,ret = 0; if (init_handle(&nlh) != 0) { return -1; } iface_idx = if_nametoindex(interface); if (iface_idx < 0) { return -1; } addr = rtnl_addr_alloc (); if (!addr) { return -1; } if (inet_pton(AF_INET, ip4addr, &binaddr) == 0) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "not valid ip address\n"); ret = -1; goto out; } nl_addr = nl_addr_build (AF_INET, &binaddr, sizeof(binaddr)); if (!nl_addr) { ret = -1; goto out; } rtnl_addr_set_local (addr, nl_addr); nl_addr_put (nl_addr); rtnl_addr_set_ifindex (addr, iface_idx); switch (cmd) { case ADD_IP: err = rtnl_addr_add (nlh, addr, 0); if ( err == -17 ) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "%s is already on %s interface\n", ip4addr, interface); ret = 0; } else if ( err < 0 ) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "error %d returned from rtnl_addr_add():\n%s\n", err, nl_geterror()); ret = -1; } else { ret = 0; } break; case DEL_IP: err = rtnl_addr_delete (nlh, addr, 0); if (err == -99) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "%s is not present on %s interface\n", ip4addr, interface); ret = 0; } else if (err < 0) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "error %d returned from rtnl_addr_delete():\n%s\n", err, nl_geterror()); ret = -1; } else { ret = 0; } break; } out: if (addr) { rtnl_addr_put (addr); } if (nlh) { nl_close(nlh); nl_handle_destroy(nlh); } return ret; }
TError TNlLink::AddXVlan(const std::string &vlantype, const std::string &master, uint32_t type, const std::string &hw, int mtu) { TError error = TError::Success(); int ret; uint32_t masterIdx; struct nl_msg *msg; struct nlattr *linkinfo, *infodata; struct ifinfomsg ifi = { 0 }; struct ether_addr *ea = nullptr; auto Name = GetName(); if (hw.length()) { // FIXME THREADS ea = ether_aton(hw.c_str()); if (!ea) return TError(EError::Unknown, "Invalid " + vlantype + " mac address " + hw); } TNlLink masterLink(Nl, master); error = masterLink.Load(); if (error) return error; masterIdx = masterLink.GetIndex(); msg = nlmsg_alloc_simple(RTM_NEWLINK, NLM_F_CREATE); if (!msg) return TError(EError::Unknown, "Unable to add " + vlantype + ": no memory"); ret = nlmsg_append(msg, &ifi, sizeof(ifi), NLMSG_ALIGNTO); if (ret < 0) { error = TError(EError::Unknown, "Unable to add " + vlantype + ": " + nl_geterror(ret)); goto free_msg; } /* link configuration */ ret = nla_put(msg, IFLA_LINK, sizeof(uint32_t), &masterIdx); if (ret < 0) { error = TError(EError::Unknown, std::string("Unable to put IFLA_LINK: ") + nl_geterror(ret)); goto free_msg; } ret = nla_put(msg, IFLA_IFNAME, Name.length() + 1, Name.c_str()); if (ret < 0) { error = TError(EError::Unknown, std::string("Unable to put IFLA_IFNAME: ") + nl_geterror(ret)); goto free_msg; } if (mtu > 0) { ret = nla_put(msg, IFLA_MTU, sizeof(int), &mtu); if (ret < 0) { error = TError(EError::Unknown, std::string("Unable to put IFLA_MTU: ") + nl_geterror(ret)); goto free_msg; } } if (ea) { struct nl_addr *addr = nl_addr_build(AF_LLC, ea, ETH_ALEN); ret = nla_put(msg, IFLA_ADDRESS, nl_addr_get_len(addr), nl_addr_get_binary_addr(addr)); if (ret < 0) { error = TError(EError::Unknown, std::string("Unable to put IFLA_ADDRESS: ") + nl_geterror(ret)); goto free_msg; } nl_addr_put(addr); } /* link type */ linkinfo = nla_nest_start(msg, IFLA_LINKINFO); if (!linkinfo) { error = TError(EError::Unknown, "Unable to add " + vlantype + ": can't nest IFLA_LINKINFO"); goto free_msg; } ret = nla_put(msg, IFLA_INFO_KIND, vlantype.length() + 1, vlantype.c_str()); if (ret < 0) { error = TError(EError::Unknown, std::string("Unable to put IFLA_INFO_KIND: ") + nl_geterror(ret)); goto free_msg; } /* xvlan specific */ infodata = nla_nest_start(msg, IFLA_INFO_DATA); if (!infodata) { error = TError(EError::Unknown, "Unable to add " + vlantype + ": can't nest IFLA_INFO_DATA"); goto free_msg; } if (vlantype == "macvlan") { ret = nla_put(msg, IFLA_MACVLAN_MODE, sizeof(uint32_t), &type); if (ret < 0) { error = TError(EError::Unknown, std::string("Unable to put IFLA_MACVLAN_MODE: ") + nl_geterror(ret)); goto free_msg; } #ifdef IFLA_IPVLAN_MAX } else if (vlantype == "ipvlan") { uint16_t mode = type; ret = nla_put(msg, IFLA_IPVLAN_MODE, sizeof(uint16_t), &mode); if (ret < 0) { error = TError(EError::Unknown, std::string("Unable to put IFLA_IPVLAN_MODE: ") + nl_geterror(ret)); goto free_msg; } #endif } nla_nest_end(msg, infodata); nla_nest_end(msg, linkinfo); L() << "netlink: add " << vlantype << " " << Name << " master " << master << " type " << type << " hw " << hw << " mtu " << mtu << std::endl; ret = nl_send_sync(GetSock(), msg); if (ret) return Error(ret, "Cannot add " + vlantype); return Load(); free_msg: nlmsg_free(msg); return error; }
int idiagnl_msg_parse(struct nlmsghdr *nlh, struct idiagnl_msg **result) { struct idiagnl_msg *msg = NULL; struct inet_diag_msg *raw_msg = NULL; struct nl_addr *src = NULL, *dst = NULL; struct nlattr *tb[IDIAG_ATTR_MAX]; int err = 0; msg = idiagnl_msg_alloc(); if (!msg) goto errout_nomem; err = nlmsg_parse(nlh, sizeof(struct inet_diag_msg), tb, IDIAG_ATTR_MAX, ext_policy); if (err < 0) goto errout; raw_msg = nlmsg_data(nlh); msg->idiag_family = raw_msg->idiag_family; msg->idiag_state = raw_msg->idiag_state; msg->idiag_timer = raw_msg->idiag_timer; msg->idiag_retrans = raw_msg->idiag_retrans; msg->idiag_expires = raw_msg->idiag_expires; msg->idiag_rqueue = raw_msg->idiag_rqueue; msg->idiag_wqueue = raw_msg->idiag_wqueue; msg->idiag_uid = raw_msg->idiag_uid; msg->idiag_inode = raw_msg->idiag_inode; msg->idiag_sport = raw_msg->id.idiag_sport; msg->idiag_dport = raw_msg->id.idiag_dport; msg->idiag_ifindex = raw_msg->id.idiag_if; dst = nl_addr_build(raw_msg->idiag_family, raw_msg->id.idiag_dst, sizeof(raw_msg->id.idiag_dst)); if (!dst) goto errout_nomem; err = idiagnl_msg_set_dst(msg, dst); if (err < 0) goto errout; nl_addr_put(dst); src = nl_addr_build(raw_msg->idiag_family, raw_msg->id.idiag_src, sizeof(raw_msg->id.idiag_src)); if (!src) goto errout_nomem; err = idiagnl_msg_set_src(msg, src); if (err < 0) goto errout; nl_addr_put(src); if (tb[IDIAG_ATTR_TOS]) msg->idiag_tos = nla_get_u8(tb[IDIAG_ATTR_TOS]); if (tb[IDIAG_ATTR_TCLASS]) msg->idiag_tclass = nla_get_u8(tb[IDIAG_ATTR_TCLASS]); if (tb[IDIAG_ATTR_SHUTDOWN]) msg->idiag_shutdown = nla_get_u8(tb[IDIAG_ATTR_SHUTDOWN]); if (tb[IDIAG_ATTR_CONG]) msg->idiag_cong = nla_strdup(tb[IDIAG_ATTR_CONG]); if (tb[IDIAG_ATTR_INFO]) nla_memcpy(&msg->idiag_tcpinfo, tb[IDIAG_ATTR_INFO], sizeof(msg->idiag_tcpinfo)); if (tb[IDIAG_ATTR_MEMINFO]) { struct idiagnl_meminfo *minfo = idiagnl_meminfo_alloc(); struct inet_diag_meminfo *raw_minfo = NULL; if (!minfo) goto errout_nomem; raw_minfo = (struct inet_diag_meminfo *) nla_data(tb[IDIAG_ATTR_MEMINFO]); idiagnl_meminfo_set_rmem(minfo, raw_minfo->idiag_rmem); idiagnl_meminfo_set_wmem(minfo, raw_minfo->idiag_wmem); idiagnl_meminfo_set_fmem(minfo, raw_minfo->idiag_fmem); idiagnl_meminfo_set_tmem(minfo, raw_minfo->idiag_tmem); msg->idiag_meminfo = minfo; } if (tb[IDIAG_ATTR_VEGASINFO]) { struct idiagnl_vegasinfo *vinfo = idiagnl_vegasinfo_alloc(); struct tcpvegas_info *raw_vinfo = NULL; if (!vinfo) goto errout_nomem; raw_vinfo = (struct tcpvegas_info *) nla_data(tb[IDIAG_ATTR_VEGASINFO]); idiagnl_vegasinfo_set_enabled(vinfo, raw_vinfo->tcpv_enabled); idiagnl_vegasinfo_set_rttcnt(vinfo, raw_vinfo->tcpv_rttcnt); idiagnl_vegasinfo_set_rtt(vinfo, raw_vinfo->tcpv_rtt); idiagnl_vegasinfo_set_minrtt(vinfo, raw_vinfo->tcpv_minrtt); msg->idiag_vegasinfo = vinfo; } if (tb[IDIAG_ATTR_SKMEMINFO]) nla_memcpy(&msg->idiag_skmeminfo, tb[IDIAG_ATTR_SKMEMINFO], sizeof(msg->idiag_skmeminfo)); *result = msg; return 0; errout: idiagnl_msg_put(msg); return err; errout_nomem: err = -NLE_NOMEM; goto errout; }
int main(int argc, char *argv[]) { struct nl_sock *nl_sock; struct nl_cache *link_cache; int ifindex; int ret = 0; int err = 0; if (argc < 2) { printf("%s ip gw on/off tip\n", argv[0]); return -1; } //link if (err = rtnl_route_read_table_names(ROUTE_TABLE)) { printf("failed to read %s. err = %s\n", ROUTE_TABLE, nl_geterror(err)); return -1;; } nl_sock = nl_socket_alloc(); if (NULL == nl_sock) { printf("failed to alloc netlink handler.\n"); return -1; } if (err = nl_connect(nl_sock, NETLINK_ROUTE)) { printf("failed to connect NETLINK_ROUTE. err = %s\n", nl_geterror(err)); ret = -1; goto release_nl; } if (err = rtnl_link_alloc_cache(nl_sock, AF_INET, &link_cache)) { printf("failed to allocate link cache. err = %s\n", nl_geterror(err)); ret = -1; goto release_nl; } ifindex = rtnl_link_name2i(link_cache, NAME); if (0 == ifindex) { printf("%s - failed to find.\n", NAME); ret = -1; goto release_link_cache; } struct rtnl_link * link = rtnl_link_get(link_cache, ifindex); if (link == NULL) { printf("can't get link.\n"); ret = -1; goto release_link_cache; } //rtnl_link_get_by_name struct nl_addr *lladdr = rtnl_link_get_addr(link); if (NULL == lladdr || AF_LLC != nl_addr_get_family(lladdr)) { printf("failed to get MAC\n"); ret = -1; goto release_link; } uint8_t mac_address[ETHER_ADDR_LEN]; memcpy(mac_address, nl_addr_get_binary_addr(lladdr), ETHER_ADDR_LEN); printf("%02X:%02X:%02X:%02X:%02X:%02X\n", mac_address[0], mac_address[1], mac_address[2], mac_address[3], mac_address[4], mac_address[5]); //addr struct nl_cache * addr_cache; if (err = rtnl_addr_alloc_cache(nl_sock, &addr_cache)) { printf("fail to get addr_cache\n"); ret = -1; goto release_link; } struct rtnl_addr *addr = rtnl_addr_alloc(); rtnl_addr_set_ifindex(addr, ifindex); rtnl_addr_set_family(addr, AF_INET); int prefixlen = 16; nl_cache_foreach_filter(addr_cache, (struct nl_object *)addr, get_ip, &prefixlen); nl_cache_free(addr_cache); uint32_t ipaddr = inet_addr(argv[1]); struct nl_addr * local = nl_addr_build(AF_INET, &ipaddr, sizeof(ipaddr)); rtnl_addr_set_local(addr, local); rtnl_addr_set_ifindex(addr, ifindex); rtnl_addr_set_family(addr, AF_INET); rtnl_addr_set_prefixlen(addr, 32); if (!strcmp(argv[2], "on")) { if (err = rtnl_addr_add(nl_sock, addr, 0)) { printf("fail to add addr %s\n", nl_geterror(err)); ret = -1; goto release_addr; } } else { if (err = rtnl_addr_delete(nl_sock, addr, 0)) { printf("fail to del addr %s\n", nl_geterror(err)); ret = -1; goto release_addr; } } //neigh struct nl_cache * neigh_cache; if (err = rtnl_neigh_alloc_cache(nl_sock, &neigh_cache)) { printf("failed to allocate neighbor cache. err = %s\n", nl_geterror(err)); ret = -1; goto release_neigh_cache; } uint32_t gw = inet_addr(argv[3]); struct nl_addr * gw_addr = nl_addr_build(AF_INET, &gw, sizeof(gw)); struct rtnl_neigh * neigh = rtnl_neigh_get(neigh_cache, ifindex, gw_addr); if (neigh) { // It's optional struct nl_addr * lladdr = rtnl_neigh_get_lladdr(neigh); if (lladdr) { uint8_t mac_address[ETHER_ADDR_LEN]; memcpy(mac_address, nl_addr_get_binary_addr(lladdr), ETHER_ADDR_LEN); printf("gw %02X:%02X:%02X:%02X:%02X:%02X\n", mac_address[0], mac_address[1], mac_address[2], mac_address[3], mac_address[4], mac_address[5]); } } nl_addr_put(gw_addr); //route struct nl_cache *route_cache; if (err = rtnl_route_alloc_cache(nl_sock, AF_INET, 0, &route_cache)) { printf("failed to allocate route cache. err = %s\n", nl_geterror(err)); ret = -1; goto release_neigh_cache; } struct rtnl_route *route = rtnl_route_alloc(); struct nl_addr * taddr; err = nl_addr_parse(argv[4], AF_INET, &taddr); if (err) { printf("failed to get taddr. err = %s\n", nl_geterror(err)); ret = -1; goto release_route_cache; } nl_cache_foreach_filter(route_cache, OBJ_CAST(route), get_route, NULL); /* struct nl_sock *nl_fib_sock; nl_fib_sock = nl_socket_alloc(); if (err = nl_connect(nl_fib_sock, NETLINK_FIB_LOOKUP)) { printf("failed to connect NETLINK_ROUTE. err = %s\n", nl_geterror(err)); ret = -1; goto release_nl; } struct nl_dump_params params = { .dp_fd = stdout, .dp_type = NL_DUMP_DETAILS, }; struct nl_cache *route_cache = flnl_result_alloc_cache(); struct flnl_request *req = flnl_request_alloc(); struct nl_addr * taddr; err = nl_addr_parse(argv[4], AF_INET, &taddr); if (err) { printf("failed to get taddr. err = %s\n", nl_geterror(err)); ret = -1; goto release_route; } int table = RT_TABLE_UNSPEC, scope = RT_SCOPE_UNIVERSE; flnl_request_set_addr(req, taddr); flnl_request_set_table(req, table); flnl_request_set_scope(req, scope); err = flnl_lookup(nl_fib_sock, req, route_cache); if (err) { printf("failed to fib lookup. err = %s\n", nl_geterror(err)); ret = -1; goto release_route_addr; } nl_cache_dump(route_cache, ¶ms); release_route_addr: nl_addr_put(taddr); release_route: nl_cache_free(route_cache); nl_object_put(OBJ_CAST(req)); nl_close(nl_fib_sock); nl_socket_free(nl_fib_sock); */ release_route_cache: nl_cache_free(route_cache); release_neigh_cache: nl_cache_free(neigh_cache); release_addr: nl_addr_put(local); rtnl_addr_put(addr); release_link: rtnl_link_put(link); release_link_cache: nl_cache_free(link_cache); release_nl: nl_close(nl_sock); nl_socket_free(nl_sock); return ret; }
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; }
static void inet6_dump_details(struct rtnl_link *link, struct nl_dump_params *p, void *data) { struct inet6_data *i6 = data; struct nl_addr *addr; char buf[64], buf2[64]; int i, n = 0; nl_dump_line(p, " ipv6 max-reasm-len %s", nl_size2str(i6->i6_cacheinfo.max_reasm_len, buf, sizeof(buf))); nl_dump(p, " <%s>\n", inet6_flags2str(i6->i6_flags, buf, sizeof(buf))); nl_dump_line(p, " create-stamp %.2fs reachable-time %s", (double) i6->i6_cacheinfo.tstamp / 100., nl_msec2str(i6->i6_cacheinfo.reachable_time, buf, sizeof(buf))); nl_dump(p, " retrans-time %s\n", nl_msec2str(i6->i6_cacheinfo.retrans_time, buf, sizeof(buf))); addr = nl_addr_build(AF_INET6, &i6->i6_token, sizeof(i6->i6_token)); nl_dump(p, " token %s\n", nl_addr2str(addr, buf, sizeof(buf))); nl_addr_put(addr); nl_dump(p, " link-local address mode %s\n", rtnl_link_inet6_addrgenmode2str(i6->i6_addr_gen_mode, buf, sizeof(buf))); nl_dump_line(p, " devconf:\n"); nl_dump_line(p, " "); for (i = 0; i < DEVCONF_MAX; i++) { uint32_t value = i6->i6_conf[i]; int x, offset; switch (i) { case DEVCONF_TEMP_VALID_LFT: case DEVCONF_TEMP_PREFERED_LFT: nl_msec2str((uint64_t) value * 1000., buf2, sizeof(buf2)); break; case DEVCONF_RTR_PROBE_INTERVAL: case DEVCONF_RTR_SOLICIT_INTERVAL: case DEVCONF_RTR_SOLICIT_DELAY: nl_msec2str(value, buf2, sizeof(buf2)); break; default: snprintf(buf2, sizeof(buf2), "%u", value); break; } inet6_devconf2str(i, buf, sizeof(buf)); offset = 23 - strlen(buf2); if (offset < 0) offset = 0; for (x = strlen(buf); x < offset; x++) buf[x] = ' '; strncpy(&buf[offset], buf2, strlen(buf2)); nl_dump_line(p, "%s", buf); if (++n == 3) { nl_dump(p, "\n"); nl_dump_line(p, " "); n = 0; } else nl_dump(p, " "); } if (n != 0) nl_dump(p, "\n"); }