void netlink_neigh_info::fill(struct rtnl_neigh* neigh) { if (!neigh) return; nl_addr* addr; char addr_str[ADDR_MAX_STR_LEN + 1]; addr = rtnl_neigh_get_dst(neigh); if (addr) { dst_addr_str = nl_addr2str(addr, addr_str, ADDR_MAX_STR_LEN); dst_addr = (unsigned char*)nl_addr_get_binary_addr(addr); dst_addr_len = nl_addr_get_len(addr); } addr = rtnl_neigh_get_lladdr(neigh); if (addr) { lladdr_str = nl_addr2str(addr, addr_str, ADDR_MAX_STR_LEN); lladdr = (unsigned char*)nl_addr_get_binary_addr(addr); lladdr_len = nl_addr_get_len(addr); } //addr_family = rtnl_neigh_get_family(neigh); flags = rtnl_neigh_get_flags(neigh); ifindex = rtnl_neigh_get_ifindex(neigh); state = rtnl_neigh_get_state(neigh); type = rtnl_neigh_get_type(neigh); }
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; }
void nl_bridge::add_neigh_to_fdb(rtnl_neigh *neigh) { assert(sw); assert(neigh); uint32_t port = nl->get_port_id(rtnl_neigh_get_ifindex(neigh)); if (port == 0) { VLOG(1) << __FUNCTION__ << ": unknown port for neigh " << OBJ_CAST(neigh); return; } nl_addr *mac = rtnl_neigh_get_lladdr(neigh); int vlan = rtnl_neigh_get_vlan(neigh); bool permanent = true; // for sure this is master (sw bridged) if (rtnl_neigh_get_master(neigh) && !(rtnl_neigh_get_flags(neigh) & NTF_MASTER)) { rtnl_neigh_set_flags(neigh, NTF_MASTER); } // check if entry already exists in cache if (is_mac_in_l2_cache(neigh)) { permanent = false; } rofl::caddress_ll _mac((uint8_t *)nl_addr_get_binary_addr(mac), nl_addr_get_len(mac)); LOG(INFO) << __FUNCTION__ << ": add mac=" << _mac << " to bridge " << rtnl_link_get_name(bridge) << " on port=" << port << " vlan=" << (unsigned)vlan << ", permanent=" << permanent; LOG(INFO) << __FUNCTION__ << ": object: " << OBJ_CAST(neigh); sw->l2_addr_add(port, vlan, _mac, true, permanent); }
static void find_one_address (struct nl_object *object, void *user_data) { FindAddrInfo *info = user_data; struct rtnl_addr *addr = (struct rtnl_addr *) object; struct nl_addr *local; void *binaddr; if (info->found) return; if (rtnl_addr_get_ifindex (addr) != info->ifindex) return; if (rtnl_addr_get_family (addr) != info->family) return; if (rtnl_addr_get_prefixlen (addr) != info->prefix) return; local = rtnl_addr_get_local (addr); if (nl_addr_get_family (local) != info->family) return; if (nl_addr_get_len (local) != info->addrlen) return; binaddr = nl_addr_get_binary_addr (local); if (binaddr) { if (memcmp (binaddr, info->addr, info->addrlen) == 0) info->found = TRUE; /* Yay, found it */ } }
/** * libnl callback function. Does the real parsing of a record returned by NETLINK. This function * parses LINK related packets * * @param obj Pointer to a struct nl_object response * @param arg Pointer to a struct etherinfo element where the parse result will be saved */ static void callback_nl_link(struct nl_object *obj, void *arg) { struct etherinfo *ethi = (struct etherinfo *) arg; struct rtnl_link *link = (struct rtnl_link *) obj; struct nl_addr *addr = rtnl_link_get_addr(link); unsigned int i, len; unsigned char *binaddr; char hwaddr[130], *ptr; if( (ethi == NULL) || (ethi->hwaddress != NULL) || (addr == NULL) ) { return; } binaddr = nl_addr_get_binary_addr(addr); memset(&hwaddr, 0, 130); len = 20; ptr = (char *)&hwaddr; for( i = 0; i < 6; i++ ) { if( i == 0 ) { snprintf(ptr, len, "%02X", *(binaddr+i)); len -= 2; ptr += 2; } else { snprintf(ptr, len, ":%02X", *(binaddr+i)); len -= 3; ptr += 3; } } SET_STR_VALUE(ethi->hwaddress, hwaddr); }
static void get_ip(struct nl_object *obj, void *arg) { struct rtnl_addr * addr = (struct rtnl_addr *) obj; struct nl_addr *naddr = rtnl_addr_get_local(addr); int prefixlen = rtnl_addr_get_prefixlen(addr); if ((NULL != naddr) && (prefixlen == *(int*)(arg))) printf("ip is 0x%x\n", *(uint32_t *) (nl_addr_get_binary_addr(naddr))); }
static void get_route(struct nl_object *obj, void *arg) { struct rtnl_route *route = (struct rtnl_route *) obj; struct rtnl_nexthop * nexthop = rtnl_route_nexthop_n(route, 0); struct nl_addr *naddr = rtnl_route_nh_get_gateway(nexthop); if (NULL != naddr) printf("gwip is 0x%x\n", *(uint32_t *) (nl_addr_get_binary_addr(naddr))); }
static void dump_route (struct rtnl_route *route) { char buf6[INET6_ADDRSTRLEN]; char buf4[INET_ADDRSTRLEN]; struct nl_addr *nl; struct in6_addr *addr6 = NULL; struct in_addr *addr4 = NULL; int prefixlen = 0; const char *sf = "UNSPEC"; int family = rtnl_route_get_family (route); guint32 log_level = LOGD_IP4 | LOGD_IP6; memset (buf6, 0, sizeof (buf6)); memset (buf4, 0, sizeof (buf4)); nl = rtnl_route_get_dst (route); if (nl) { if (nl_addr_get_family (nl) == AF_INET) { addr4 = nl_addr_get_binary_addr (nl); if (addr4) inet_ntop (AF_INET, addr4, &buf4[0], sizeof (buf4)); } else if (nl_addr_get_family (nl) == AF_INET6) { addr6 = nl_addr_get_binary_addr (nl); if (addr6) inet_ntop (AF_INET6, addr6, &buf6[0], sizeof (buf6)); } prefixlen = nl_addr_get_prefixlen (nl); } if (family == AF_INET) { sf = "INET"; log_level = LOGD_IP4; } else if (family == AF_INET6) { sf = "INET6"; log_level = LOGD_IP6; } nm_log_dbg (log_level, " route idx %d family %s (%d) addr %s/%d", rtnl_route_get_oif (route), sf, family, strlen (buf4) ? buf4 : (strlen (buf6) ? buf6 : "<unknown>"), prefixlen); }
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 Option<net::IP> IP(nl_addr* _ip) { Option<net::IP> result; if (_ip != NULL && nl_addr_get_len(_ip) != 0) { struct in_addr* addr = (struct in_addr*) nl_addr_get_binary_addr(_ip); result = net::IP(*addr); } return result; }
static void check_addresses (NMIP6Device *device) { NMIP6Manager *manager = device->manager; NMIP6ManagerPrivate *priv = NM_IP6_MANAGER_GET_PRIVATE (manager); struct rtnl_addr *rtnladdr; struct nl_addr *nladdr; struct in6_addr *addr; /* Reset address information */ device->has_linklocal = FALSE; device->has_nonlinklocal = FALSE; /* Look for any IPv6 addresses the kernel may have set for the device */ for (rtnladdr = (struct rtnl_addr *) nl_cache_get_first (priv->addr_cache); rtnladdr; rtnladdr = (struct rtnl_addr *) nl_cache_get_next ((struct nl_object *) rtnladdr)) { char buf[INET6_ADDRSTRLEN]; if (rtnl_addr_get_ifindex (rtnladdr) != device->ifindex) continue; nladdr = rtnl_addr_get_local (rtnladdr); if (!nladdr || nl_addr_get_family (nladdr) != AF_INET6) continue; addr = nl_addr_get_binary_addr (nladdr); if (inet_ntop (AF_INET6, addr, buf, INET6_ADDRSTRLEN) > 0) { nm_log_dbg (LOGD_IP6, "(%s): netlink address: %s/%d", device->iface, buf, rtnl_addr_get_prefixlen (rtnladdr)); } if (IN6_IS_ADDR_LINKLOCAL (addr)) { if (device->state == NM_IP6_DEVICE_UNCONFIGURED) device_set_state (device, NM_IP6_DEVICE_GOT_LINK_LOCAL); device->has_linklocal = TRUE; } else { if (device->state == NM_IP6_DEVICE_GOT_ROUTER_ADVERTISEMENT) device_set_state (device, NM_IP6_DEVICE_GOT_ADDRESS); device->has_nonlinklocal = TRUE; } } /* There might be a LL address hanging around on the interface from * before in the initial run, but if it goes away later, make sure we * regress from GOT_LINK_LOCAL back to UNCONFIGURED. */ if ((device->state == NM_IP6_DEVICE_GOT_LINK_LOCAL) && !device->has_linklocal) device_set_state (device, NM_IP6_DEVICE_UNCONFIGURED); nm_log_dbg (LOGD_IP6, "(%s): addresses checked (state %s)", device->iface, state_to_string (device->state)); }
/** * libnl callback function. Does the real parsing of a record returned by NETLINK. This function * parses ADDRESS related packets * * @param obj Pointer to a struct nl_object response * @param arg Pointer to a struct etherinfo element where the parse result will be saved */ static void callback_nl_address(struct nl_object *obj, void *arg) { struct etherinfo *ethi = (struct etherinfo *) arg; struct nl_addr *addr; char ip_str[66]; int family; if( ethi == NULL ) { return; } addr = rtnl_addr_get_local((struct rtnl_addr *)obj); family = nl_addr_get_family(addr); switch( family ) { case AF_INET: case AF_INET6: memset(&ip_str, 0, 66); inet_ntop(family, nl_addr_get_binary_addr(addr), (char *)&ip_str, 64); if( family == AF_INET ) { struct nl_addr *brdcst = rtnl_addr_get_broadcast((struct rtnl_addr *)obj); char brdcst_str[66]; SET_STR_VALUE(ethi->ipv4_address, ip_str); ethi->ipv4_netmask = rtnl_addr_get_prefixlen((struct rtnl_addr*) obj); if( brdcst ) { memset(&brdcst_str, 0, 66); inet_ntop(family, nl_addr_get_binary_addr(brdcst), (char *)&brdcst_str, 64); SET_STR_VALUE(ethi->ipv4_broadcast, brdcst_str); } } else { ethi->ipv6_addresses = etherinfo_add_ipv6(ethi->ipv6_addresses, ip_str, rtnl_addr_get_prefixlen((struct rtnl_addr*) obj), rtnl_addr_get_scope((struct rtnl_addr*) obj)); } return; default: return; } }
/** * Set IPv6 tokenized interface identifier * @arg link Link object * @arg token Tokenized interface identifier * * Sets the link's IPv6 tokenized interface identifier. * * @return 0 on success * @return -NLE_NOMEM could not allocate inet6 data * @return -NLE_INVAL addr is not a valid inet6 address */ int rtnl_link_inet6_set_token(struct rtnl_link *link, struct nl_addr *addr) { struct inet6_data *id; if ((nl_addr_get_family(addr) != AF_INET6) || (nl_addr_get_len(addr) != sizeof(id->i6_token))) return -NLE_INVAL; if (!(id = rtnl_link_af_alloc(link, &inet6_ops))) return -NLE_NOMEM; memcpy(&id->i6_token, nl_addr_get_binary_addr(addr), sizeof(id->i6_token)); return 0; }
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; }
static void foreach_route_cb (struct nl_object *object, void *user_data) { ForeachRouteInfo *info = user_data; struct rtnl_route *route = (struct rtnl_route *) object; struct nl_addr *dst; if (info->out_route) return; if (nm_logging_level_enabled (LOGL_DEBUG)) dump_route (route); if ( info->ifindex > 0 && rtnl_route_get_oif (route) != info->ifindex) return; if ( info->scope != RT_SCOPE_UNIVERSE && rtnl_route_get_scope (route) != info->scope) return; if ( info->family != AF_UNSPEC && rtnl_route_get_family (route) != info->family) return; dst = rtnl_route_get_dst (route); /* Check for IPv6 LL and MC routes that might need to be ignored */ if ( (info->family == AF_INET6 || info->family == AF_UNSPEC) && (rtnl_route_get_family (route) == AF_INET6)) { struct in6_addr *addr = NULL; if (dst) addr = nl_addr_get_binary_addr (dst); if (addr) { if ( IN6_IS_ADDR_LINKLOCAL (addr) || IN6_IS_ADDR_MC_LINKLOCAL (addr) || (IN6_IS_ADDR_MULTICAST (addr) && (nl_addr_get_prefixlen (dst) == 8))) return; } } info->out_route = info->callback (route, dst, info->iface, info->user_data); if (info->out_route) { /* Ref the route so it sticks around after the cache is cleared */ rtnl_route_get (info->out_route); } }
static int get_hwaddr (int ifindex, guint8 *buf) { struct rtnl_link *lk; struct nl_addr *addr; int len; lk = nm_netlink_index_to_rtnl_link (ifindex); if (!lk) return -1; addr = rtnl_link_get_addr (lk); len = nl_addr_get_len (addr); if (len > NM_UTILS_HWADDR_LEN_MAX) len = -1; else memcpy (buf, nl_addr_get_binary_addr (addr), len); rtnl_link_put (lk); return len; }
/** * Builds a netlink request message to do a lookup * @arg req Requested match. * @arg flags additional netlink message flags * @arg result Result pointer * * Builds a new netlink message requesting a change of link attributes. * The netlink message header isn't fully equipped with all relevant * fields and must be sent out via nl_send_auto_complete() or * supplemented as needed. * \a old must point to a link currently configured in the kernel * and \a tmpl must contain the attributes to be changed set via * \c rtnl_link_set_* functions. * * @return 0 on success or a negative error code. */ int flnl_lookup_build_request(struct flnl_request *req, int flags, struct nl_msg **result) { struct nl_msg *msg; struct nl_addr *addr; uint64_t fwmark; int tos, scope, table; struct fib_result_nl fr = {0}; fwmark = flnl_request_get_fwmark(req); tos = flnl_request_get_tos(req); scope = flnl_request_get_scope(req); table = flnl_request_get_table(req); fr.fl_fwmark = fwmark != UINT_LEAST64_MAX ? fwmark : 0; fr.fl_tos = tos >= 0 ? tos : 0; fr.fl_scope = scope >= 0 ? scope : RT_SCOPE_UNIVERSE; fr.tb_id_in = table >= 0 ? table : RT_TABLE_UNSPEC; addr = flnl_request_get_addr(req); if (!addr) return -NLE_MISSING_ATTR; fr.fl_addr = *(uint32_t *) nl_addr_get_binary_addr(addr); msg = nlmsg_alloc_simple(0, flags); if (!msg) return -NLE_NOMEM; if (nlmsg_append(msg, &fr, sizeof(fr), NLMSG_ALIGNTO) < 0) goto errout; *result = msg; return 0; errout: nlmsg_free(msg); return -NLE_MSGSIZE; }
/** * Builds a netlink request message to do a lookup * @arg req Requested match. * @arg flags additional netlink message flags * * Builds a new netlink message requesting a change of link attributes. * The netlink message header isn't fully equipped with all relevant * fields and must be sent out via nl_send_auto_complete() or * supplemented as needed. * \a old must point to a link currently configured in the kernel * and \a tmpl must contain the attributes to be changed set via * \c rtnl_link_set_* functions. * * @return New netlink message * @note Not all attributes can be changed, see * \ref link_changeable "Changeable Attributes" for more details. */ struct nl_msg *flnl_lookup_build_request(struct flnl_request *req, int flags) { struct nl_msg *msg; struct nl_addr *addr; uint64_t fwmark; int tos, scope, table; struct fib_result_nl fr = {0}; fwmark = flnl_request_get_fwmark(req); tos = flnl_request_get_tos(req); scope = flnl_request_get_scope(req); table = flnl_request_get_table(req); fr.fl_fwmark = fwmark != UINT_LEAST64_MAX ? fwmark : 0; fr.fl_tos = tos >= 0 ? tos : 0; fr.fl_scope = scope >= 0 ? scope : RT_SCOPE_UNIVERSE; fr.tb_id_in = table >= 0 ? table : RT_TABLE_UNSPEC; addr = flnl_request_get_addr(req); if (!addr) { nl_error(EINVAL, "Request must specify the address"); return NULL; } fr.fl_addr = *(uint32_t *) nl_addr_get_binary_addr(addr); msg = nlmsg_alloc_simple(0, flags); if (!msg) goto errout; if (nlmsg_append(msg, &fr, sizeof(fr), NLMSG_ALIGNTO) < 0) goto errout; return msg; errout: nlmsg_free(msg); return NULL; }
int xfrmnl_ae_build_get_request(struct nl_addr* daddr, unsigned int spi, unsigned int protocol, unsigned int mark_mask, unsigned int mark_value, struct nl_msg **result) { struct nl_msg *msg; struct xfrm_aevent_id ae_id; struct xfrmnl_mark mark; if (!daddr || !spi) { fprintf(stderr, "APPLICATION BUG: %s:%d:%s: A valid destination address, spi must be specified\n", __FILE__, __LINE__, __PRETTY_FUNCTION__); assert(0); return -NLE_MISSING_ATTR; } memset(&ae_id, 0, sizeof(ae_id)); memcpy (&ae_id.sa_id.daddr, nl_addr_get_binary_addr (daddr), sizeof (uint8_t) * nl_addr_get_len (daddr)); ae_id.sa_id.spi = htonl(spi); ae_id.sa_id.family = nl_addr_get_family (daddr); ae_id.sa_id.proto = protocol; if (!(msg = nlmsg_alloc_simple(XFRM_MSG_GETAE, 0))) return -NLE_NOMEM; if (nlmsg_append(msg, &ae_id, sizeof(ae_id), NLMSG_ALIGNTO) < 0) goto nla_put_failure; mark.m = mark_mask; mark.v = mark_value; NLA_PUT (msg, XFRMA_MARK, sizeof (struct xfrmnl_mark), &mark); *result = msg; return 0; nla_put_failure: nlmsg_free(msg); return -NLE_MSGSIZE; }
static void update_hw_address (NMDevice *dev) { NMDeviceWired *self = NM_DEVICE_WIRED (dev); NMDeviceWiredPrivate *priv = NM_DEVICE_WIRED_GET_PRIVATE (self); struct rtnl_link *rtnl; struct nl_addr *addr; rtnl = nm_netlink_index_to_rtnl_link (nm_device_get_ip_ifindex (dev)); if (!rtnl) { nm_log_err (LOGD_HW | NM_DEVICE_WIRED_LOG_LEVEL (dev), "(%s) failed to read hardware address (error %d)", nm_device_get_iface (dev), errno); return; } addr = rtnl_link_get_addr (rtnl); if (!addr) { nm_log_err (LOGD_HW | NM_DEVICE_WIRED_LOG_LEVEL (dev), "(%s) no hardware address?", nm_device_get_iface (dev)); rtnl_link_put (rtnl); return; } if (nl_addr_get_len (addr) != priv->hw_addr_len) { nm_log_err (LOGD_HW | NM_DEVICE_WIRED_LOG_LEVEL (dev), "(%s) hardware address is wrong length (expected %d got %d)", nm_device_get_iface (dev), priv->hw_addr_len, nl_addr_get_len (addr)); } else { memcpy (&priv->hw_addr, nl_addr_get_binary_addr (addr), priv->hw_addr_len); } rtnl_link_put (rtnl); }
void nl_bridge::remove_neigh_from_fdb(rtnl_neigh *neigh) { assert(sw); nl_addr *addr = rtnl_neigh_get_lladdr(neigh); if (nl_addr_cmp(rtnl_link_get_addr(bridge), addr) == 0) { // ignore ll addr of bridge on slave return; } // lookup l2_cache as well std::unique_ptr<rtnl_neigh, decltype(&rtnl_neigh_put)> n_lookup( NEIGH_CAST(nl_cache_search(l2_cache.get(), OBJ_CAST(neigh))), rtnl_neigh_put); if (n_lookup) { nl_cache_remove(OBJ_CAST(n_lookup.get())); } const uint32_t port = nl->get_port_id(rtnl_neigh_get_ifindex(neigh)); rofl::caddress_ll mac((uint8_t *)nl_addr_get_binary_addr(addr), nl_addr_get_len(addr)); sw->l2_addr_remove(port, rtnl_neigh_get_vlan(neigh), mac); }
static struct nl_msg *build_addr_msg(struct rtnl_addr *tmpl, int cmd, int flags) { struct nl_msg *msg; struct ifaddrmsg am = { .ifa_family = tmpl->a_family, .ifa_index = tmpl->a_ifindex, .ifa_prefixlen = tmpl->a_prefixlen, }; if (tmpl->a_mask & ADDR_ATTR_FLAGS) am.ifa_flags = tmpl->a_flags; if (tmpl->a_mask & ADDR_ATTR_SCOPE) am.ifa_scope = tmpl->a_scope; else { /* compatibility hack */ if (tmpl->a_family == AF_INET && tmpl->a_mask & ADDR_ATTR_LOCAL && *((char *) nl_addr_get_binary_addr(tmpl->a_local)) == 127) am.ifa_scope = RT_SCOPE_HOST; else am.ifa_scope = RT_SCOPE_UNIVERSE; } msg = nlmsg_build_simple(cmd, flags); if (!msg) goto nla_put_failure; if (nlmsg_append(msg, &am, sizeof(am), 1) < 0) goto nla_put_failure; if (tmpl->a_mask & ADDR_ATTR_LOCAL) NLA_PUT_ADDR(msg, IFA_LOCAL, tmpl->a_local); if (tmpl->a_mask & ADDR_ATTR_PEER) NLA_PUT_ADDR(msg, IFA_ADDRESS, tmpl->a_peer); else NLA_PUT_ADDR(msg, IFA_ADDRESS, tmpl->a_local); if (tmpl->a_mask & ADDR_ATTR_LABEL) NLA_PUT_STRING(msg, IFA_LABEL, tmpl->a_label); if (tmpl->a_mask & ADDR_ATTR_BROADCAST) NLA_PUT_ADDR(msg, IFA_BROADCAST, tmpl->a_bcast); if (tmpl->a_mask & ADDR_ATTR_ANYCAST) NLA_PUT_ADDR(msg, IFA_ANYCAST, tmpl->a_anycast); return msg; nla_put_failure: nlmsg_free(msg); return NULL; } /** * @name Address Addition * @{ */ /** * Build netlink request message to request addition of new address * @arg addr Address object representing the new address. * @arg flags Additional netlink message flags. * * Builds a new netlink message requesting the addition of a new * address. 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. * * Minimal required attributes: * - interface index (rtnl_addr_set_ifindex()) * - local address (rtnl_addr_set_local()) * * The scope will default to universe except for loopback addresses in * which case a host scope is used if not specified otherwise. * * @note Free the memory after usage using nlmsg_free(). * @return Newly allocated netlink message or NULL if an error occured. */ struct nl_msg *rtnl_addr_build_add_request(struct rtnl_addr *addr, int flags) { int required = ADDR_ATTR_IFINDEX | ADDR_ATTR_FAMILY | ADDR_ATTR_PREFIXLEN | ADDR_ATTR_LOCAL; if ((addr->a_mask & required) != required) { nl_error(EINVAL, "Missing mandatory attributes, required are: " "ifindex, family, prefixlen, local address."); return NULL; } return build_addr_msg(addr, RTM_NEWADDR, NLM_F_CREATE | flags); }
static void route_proc_cb(struct nl_object *c, void *arg) { struct ip_lookup_res *res = (struct ip_lookup_res*) arg; struct rtnl_route *route = (struct rtnl_route *) c; struct nl_cache *link_cache; struct nl_addr *addr; struct rtnl_nexthop *nh; int prefix_len; int oif; char buf[64]; link_cache = nl_cache_mngt_require("route/link"); addr = rtnl_route_get_dst(route); if (addr) { printf("%s", nl_addr2str(addr, buf, sizeof(buf))); res->dstaddr = *(uint32_t *) nl_addr_get_binary_addr(addr); } prefix_len = rtnl_route_get_dst_len(route); if (prefix_len) printf("/%d ", prefix_len); else printf("default "); addr = rtnl_route_get_src(route); if (addr) printf("src %s ", nl_addr2str(addr, buf, sizeof(buf))); addr = rtnl_route_get_pref_src(route); if (addr) printf("preferred src %s ", nl_addr2str(addr, buf, sizeof(buf))); addr = rtnl_route_get_gateway(route); if (addr) { printf("via %s ", nl_addr2str(addr, buf, sizeof(buf))); res->nh_addr = *(uint32_t*) nl_addr_get_binary_addr(addr); } else { res->nh_addr = 0; } oif = rtnl_route_get_oif(route); res->oif = oif; if (oif != RTNL_LINK_NOT_FOUND && link_cache) { printf("dev %s ", rtnl_link_i2name(link_cache, oif, buf, sizeof(buf))); rtnl_link_i2name(link_cache, oif, res->oifname, sizeof(res->oifname)); } /* Declaration of rtnl_route_nh_get_gateway() is missing from * include/netlink/route/nexthop.h, there is no way to inspect * each nexthop for gateway information, will just use gateway * info stored in rtnl_route struct. The probem is only present * libnl 1 */ /* nl_list_for_each_entry(nh, rtnl_route_get_nexthops(route), rtnh_list) { } */ printf("\n"); }
static int build_xfrm_ae_message(struct xfrmnl_ae *tmpl, int cmd, int flags, struct nl_msg **result) { struct nl_msg* msg; struct xfrm_aevent_id ae_id; if (!(tmpl->ce_mask & XFRM_AE_ATTR_DADDR) || !(tmpl->ce_mask & XFRM_AE_ATTR_SPI) || !(tmpl->ce_mask & XFRM_AE_ATTR_PROTO)) return -NLE_MISSING_ATTR; memcpy (&ae_id.sa_id.daddr, nl_addr_get_binary_addr (tmpl->sa_id.daddr), sizeof (uint8_t) * nl_addr_get_len (tmpl->sa_id.daddr)); ae_id.sa_id.spi = htonl(tmpl->sa_id.spi); ae_id.sa_id.family = tmpl->sa_id.family; ae_id.sa_id.proto = tmpl->sa_id.proto; if (tmpl->ce_mask & XFRM_AE_ATTR_SADDR) memcpy (&ae_id.saddr, nl_addr_get_binary_addr (tmpl->saddr), sizeof (uint8_t) * nl_addr_get_len (tmpl->saddr)); if (tmpl->ce_mask & XFRM_AE_ATTR_FLAGS) ae_id.flags = tmpl->flags; if (tmpl->ce_mask & XFRM_AE_ATTR_REQID) ae_id.reqid = tmpl->reqid; msg = nlmsg_alloc_simple(cmd, flags); if (!msg) return -NLE_NOMEM; if (nlmsg_append(msg, &ae_id, sizeof(ae_id), NLMSG_ALIGNTO) < 0) goto nla_put_failure; if (tmpl->ce_mask & XFRM_AE_ATTR_MARK) NLA_PUT (msg, XFRMA_MARK, sizeof (struct xfrmnl_mark), &tmpl->mark); if (tmpl->ce_mask & XFRM_AE_ATTR_LIFETIME) NLA_PUT (msg, XFRMA_LTIME_VAL, sizeof (struct xfrmnl_lifetime_cur), &tmpl->lifetime_cur); if (tmpl->ce_mask & XFRM_AE_ATTR_REPLAY_MAXAGE) NLA_PUT_U32 (msg, XFRMA_ETIMER_THRESH, tmpl->replay_maxage); if (tmpl->ce_mask & XFRM_AE_ATTR_REPLAY_MAXDIFF) NLA_PUT_U32 (msg, XFRMA_REPLAY_THRESH, tmpl->replay_maxdiff); if (tmpl->ce_mask & XFRM_AE_ATTR_REPLAY_STATE) { if (tmpl->replay_state_esn) { uint32_t len = sizeof (struct xfrm_replay_state_esn) + (sizeof (uint32_t) * tmpl->replay_state_esn->bmp_len); NLA_PUT (msg, XFRMA_REPLAY_ESN_VAL, len, tmpl->replay_state_esn); } else { NLA_PUT (msg, XFRMA_REPLAY_VAL, sizeof (struct xfrmnl_replay_state), &tmpl->replay_state); } } *result = msg; return 0; nla_put_failure: nlmsg_free(msg); return -NLE_MSGSIZE; }
CAMLprim value ocaml_get_routing_table(value unit) { CAMLparam1(unit); CAMLlocal3( ret, tmp, entry ); struct nl_sock *fd; struct nl_cache *res, *links; struct rtnl_route *it; uint32 i_ip, netmask = 0, mask_len, gw; int i; struct nl_addr *ip; char device_name[IFNAMSIZ]; struct rtnl_nexthop *to; fd = nl_socket_alloc(); if (!fd) { fprintf(stderr, "error nl_socket_alloc\n"); exit(1); } if(nl_connect(fd, NETLINK_ROUTE) < 0) { fprintf(stderr, "error nl_connect\n"); exit(1); } ret = Val_emptylist; if(rtnl_route_alloc_cache(fd, AF_UNSPEC, 0, &res) < 0) { fprintf(stderr, "error rtnl_route_alloc_cache"); exit(1); } if(rtnl_link_alloc_cache (fd, AF_UNSPEC, &links) < 0) { fprintf(stderr, "error rtnl_link_alloc_cache"); exit(1); } it = (struct rtnl_route *)nl_cache_get_first(res); for(; it != NULL; it = (struct rtnl_route *) nl_cache_get_next((struct nl_object *)it) ) { if(rtnl_route_get_family (it) == AF_INET) { ip = rtnl_route_get_dst(it); i_ip = ntohl(*(int *)nl_addr_get_binary_addr(ip)); mask_len = nl_addr_get_prefixlen(ip); for(i = 0; i < 32; i++) netmask = (netmask << 1) + (i< mask_len?1:0); to = rtnl_route_nexthop_n(it, 0); rtnl_link_i2name(links, rtnl_route_nh_get_ifindex(to), device_name, IFNAMSIZ); if ( rtnl_route_nh_get_gateway (to) != NULL) gw = ntohl(*(int *)nl_addr_get_binary_addr( rtnl_route_nh_get_gateway (to))); else gw = 0; /*printf("src ip:%x mask:%x gw:%x dev:%s\n", i_ip, netmask, */ /*gw, device_name);*/ entry = caml_alloc(7,0); Store_field(entry, 0, Val_int(i_ip & 0xFFFF)); Store_field(entry, 1, Val_int(i_ip >> 16)); Store_field(entry, 2, Val_int(netmask & 0xFFFF)); Store_field(entry, 3, Val_int(netmask >> 16)); Store_field(entry, 4, Val_int(gw & 0xFFFF)); Store_field(entry, 5, Val_int(gw >> 16)); Store_field(entry, 6, caml_copy_string(device_name)); // store in list tmp = caml_alloc(2, 0); Store_field( tmp, 0, entry); // head Store_field( tmp, 1, ret); // tail ret = tmp; } }
int main(int argc, char *argv[]) { char *unikernel; enum { QEMU, KVM, UKVM, UNIX } hypervisor; if (argc < 3) { fprintf(stderr, "usage: runner HYPERVISOR UNIKERNEL [ ARGS... ]\n"); fprintf(stderr, "HYPERVISOR: qemu | kvm | ukvm | unix\n"); return 1; } if (strcmp(argv[1], "qemu") == 0) hypervisor = QEMU; else if (strcmp(argv[1], "kvm") == 0) hypervisor = KVM; else if (strcmp(argv[1], "ukvm") == 0) hypervisor = UKVM; else if (strcmp(argv[1], "unix") == 0) hypervisor = UNIX; else { warnx("error: Invalid hypervisor: %s", argv[1]); return 1; } unikernel = argv[2]; /* * Remaining arguments are to be passed on to the unikernel. */ argv += 3; argc -= 3; /* * Check we have CAP_NET_ADMIN. */ if (capng_get_caps_process() != 0) { warnx("error: capng_get_caps_process() failed"); return 1; } if (!capng_have_capability(CAPNG_EFFECTIVE, CAP_NET_ADMIN)) { warnx("error: CAP_NET_ADMIN is required"); return 1; } /* * Connect to netlink, load link cache from kernel. */ struct nl_sock *sk; struct nl_cache *link_cache; int err; sk = nl_socket_alloc(); assert(sk); err = nl_connect(sk, NETLINK_ROUTE); if (err < 0) { warnx("nl_connect() failed: %s", nl_geterror(err)); return 1; } err = rtnl_link_alloc_cache(sk, AF_UNSPEC, &link_cache); if (err < 0) { warnx("rtnl_link_alloc_cache() failed: %s", nl_geterror(err)); return 1; } /* * Retrieve container network configuration -- IP address and * default gateway. */ struct rtnl_link *l_veth; l_veth = rtnl_link_get_by_name(link_cache, VETH_LINK_NAME); if (l_veth == NULL) { warnx("error: Could not get link information for %s", VETH_LINK_NAME); return 1; } struct nl_addr *veth_addr; err = get_link_inet_addr(sk, l_veth, &veth_addr); if (err) { warnx("error: Unable to determine IP address of %s", VETH_LINK_NAME); return 1; } struct nl_addr *gw_addr; err = get_default_gw_inet_addr(sk, &gw_addr); if (err) { warnx("error: get_deGfault_gw_inet_addr() failed"); return 1; } if (gw_addr == NULL) { warnx("error: No default gateway found. This is currently " "not supported"); return 1; } /* * Create bridge and tap interface, enslave veth and tap interfaces to * bridge. */ err = create_bridge_link(sk, BRIDGE_LINK_NAME); if (err < 0) { warnx("create_bridge_link(%s) failed: %s", BRIDGE_LINK_NAME, nl_geterror(err)); return 1; } int tap_fd; if (hypervisor == UKVM) err = create_tap_link(TAP_LINK_NAME, &tap_fd); else err = create_tap_link(TAP_LINK_NAME, NULL); if (err != 0) { warnx("create_tap_link(%s) failed: %s", TAP_LINK_NAME, strerror(err)); return 1; } /* Refill link cache with newly-created interfaces */ nl_cache_refill(sk, link_cache); struct rtnl_link *l_bridge; l_bridge = rtnl_link_get_by_name(link_cache, BRIDGE_LINK_NAME); if (l_bridge == NULL) { warnx("error: Could not get link information for %s", BRIDGE_LINK_NAME); return 1; } struct rtnl_link *l_tap; l_tap = rtnl_link_get_by_name(link_cache, TAP_LINK_NAME); if (l_tap == NULL) { warnx("error: Could not get link information for %s", TAP_LINK_NAME); return 1; } err = rtnl_link_enslave(sk, l_bridge, l_veth); if (err < 0) { warnx("error: Unable to enslave %s to %s: %s", VETH_LINK_NAME, BRIDGE_LINK_NAME, nl_geterror(err)); return 1; } err = rtnl_link_enslave(sk, l_bridge, l_tap); if (err < 0) { warnx("error: Unable to enslave %s to %s: %s", TAP_LINK_NAME, BRIDGE_LINK_NAME, nl_geterror(err)); return 1; } /* * Flush all IPv4 addresses from the veth interface. This is now safe * as we are good to commit and have retrieved the existing configuration. */ struct rtnl_addr *flush_addr; flush_addr = rtnl_addr_alloc(); assert(flush_addr); rtnl_addr_set_ifindex(flush_addr, rtnl_link_get_ifindex(l_veth)); rtnl_addr_set_family(flush_addr, AF_INET); rtnl_addr_set_local(flush_addr, veth_addr); err = rtnl_addr_delete(sk, flush_addr, 0); if (err < 0) { warnx("error: Could not flush addresses on %s: %s", VETH_LINK_NAME, nl_geterror(err)); return 1; } rtnl_addr_put(flush_addr); /* * Bring up the tap and bridge interfaces. */ struct rtnl_link *l_up; l_up = rtnl_link_alloc(); assert(l_up); /* You'd think set_operstate was the thing to do here. It's not. */ rtnl_link_set_flags(l_up, IFF_UP); err = rtnl_link_change(sk, l_tap, l_up, 0); if (err < 0) { warnx("error: rtnl_link_change(%s, UP) failed: %s", TAP_LINK_NAME, nl_geterror(err)); return 1; } err = rtnl_link_change(sk, l_bridge, l_up, 0); if (err < 0) { warnx("error: rtnl_link_change(%s, UP) failed: %s", BRIDGE_LINK_NAME, nl_geterror(err)); return 1; } rtnl_link_put(l_up); /* * Collect network configuration data. */ char ip[AF_INET_BUFSIZE]; if (inet_ntop(AF_INET, nl_addr_get_binary_addr(veth_addr), ip, sizeof ip) == NULL) { perror("inet_ntop()"); return 1; } char uarg_ip[AF_INET_BUFSIZE]; unsigned int prefixlen = nl_addr_get_prefixlen(veth_addr); snprintf(uarg_ip, sizeof uarg_ip, "%s/%u", ip, prefixlen); char uarg_gw[AF_INET_BUFSIZE]; if (inet_ntop(AF_INET, nl_addr_get_binary_addr(gw_addr), uarg_gw, sizeof uarg_gw) == NULL) { perror("inet_ntop()"); return 1; } /* * Build unikernel and hypervisor arguments. */ ptrvec* uargpv = pvnew(); char *uarg_buf; /* * QEMU/KVM: * /usr/bin/qemu-system-x86_64 <qemu args> -kernel <unikernel> -append "<unikernel args>" */ if (hypervisor == QEMU || hypervisor == KVM) { pvadd(uargpv, "/usr/bin/qemu-system-x86_64"); pvadd(uargpv, "-nodefaults"); pvadd(uargpv, "-no-acpi"); pvadd(uargpv, "-display"); pvadd(uargpv, "none"); pvadd(uargpv, "-serial"); pvadd(uargpv, "stdio"); pvadd(uargpv, "-m"); pvadd(uargpv, "512"); if (hypervisor == KVM) { pvadd(uargpv, "-enable-kvm"); pvadd(uargpv, "-cpu"); pvadd(uargpv, "host"); } else { /* * Required for AESNI use in Mirage. */ pvadd(uargpv, "-cpu"); pvadd(uargpv, "Westmere"); } pvadd(uargpv, "-device"); char *guest_mac = generate_mac(); assert(guest_mac); err = asprintf(&uarg_buf, "virtio-net-pci,netdev=n0,mac=%s", guest_mac); assert(err != -1); pvadd(uargpv, uarg_buf); pvadd(uargpv, "-netdev"); err = asprintf(&uarg_buf, "tap,id=n0,ifname=%s,script=no,downscript=no", TAP_LINK_NAME); assert(err != -1); pvadd(uargpv, uarg_buf); pvadd(uargpv, "-kernel"); pvadd(uargpv, unikernel); pvadd(uargpv, "-append"); /* * TODO: Replace any occurences of ',' with ',,' in -append, because * QEMU arguments are insane. */ char cmdline[1024]; char *cmdline_p = cmdline; size_t cmdline_free = sizeof cmdline; for (; *argv; argc--, argv++) { size_t alen = snprintf(cmdline_p, cmdline_free, "%s%s", *argv, (argc > 1) ? " " : ""); if (alen >= cmdline_free) { warnx("error: Command line too long"); return 1; } cmdline_free -= alen; cmdline_p += alen; } size_t alen = snprintf(cmdline_p, cmdline_free, "--ipv4=%s --ipv4-gateway=%s", uarg_ip, uarg_gw); if (alen >= cmdline_free) { warnx("error: Command line too long"); return 1; } pvadd(uargpv, cmdline); } /* * UKVM: * /unikernel/ukvm <ukvm args> <unikernel> -- <unikernel args> */ else if (hypervisor == UKVM) { pvadd(uargpv, "/unikernel/ukvm"); err = asprintf(&uarg_buf, "--net=@%d", tap_fd); assert(err != -1); pvadd(uargpv, uarg_buf); pvadd(uargpv, "--"); pvadd(uargpv, unikernel); for (; *argv; argc--, argv++) { pvadd(uargpv, *argv); } err = asprintf(&uarg_buf, "--ipv4=%s", uarg_ip); assert(err != -1); pvadd(uargpv, uarg_buf); err = asprintf(&uarg_buf, "--ipv4-gateway=%s", uarg_gw); assert(err != -1); pvadd(uargpv, uarg_buf); } /* * UNIX: * <unikernel> <unikernel args> */ else if (hypervisor == UNIX) { pvadd(uargpv, unikernel); err = asprintf(&uarg_buf, "--interface=%s", TAP_LINK_NAME); assert(err != -1); pvadd(uargpv, uarg_buf); for (; *argv; argc--, argv++) { pvadd(uargpv, *argv); } err = asprintf(&uarg_buf, "--ipv4=%s", uarg_ip); assert(err != -1); pvadd(uargpv, uarg_buf); err = asprintf(&uarg_buf, "--ipv4-gateway=%s", uarg_gw); assert(err != -1); pvadd(uargpv, uarg_buf); } char **uargv = (char **)pvfinal(uargpv); /* * Done with netlink, free all resources and close socket. */ rtnl_link_put(l_veth); rtnl_link_put(l_bridge); rtnl_link_put(l_tap); nl_addr_put(veth_addr); nl_addr_put(gw_addr); nl_cache_free(link_cache); nl_close(sk); nl_socket_free(sk); /* * Drop all capabilities except CAP_NET_BIND_SERVICE. */ capng_clear(CAPNG_SELECT_BOTH); capng_update(CAPNG_ADD, CAPNG_EFFECTIVE | CAPNG_PERMITTED | CAPNG_INHERITABLE, CAP_NET_BIND_SERVICE); if (capng_apply(CAPNG_SELECT_BOTH) != 0) { warnx("error: Could not drop capabilities"); return 1; } /* * Run the unikernel. */ err = execv(uargv[0], uargv); warn("error: execv() of %s failed", uargv[0]); return 1; }
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; }
NMIP6Config * nm_ip6_manager_get_ip6_config (NMIP6Manager *manager, int ifindex) { NMIP6ManagerPrivate *priv; NMIP6Device *device; NMIP6Config *config; struct rtnl_addr *rtnladdr; struct nl_addr *nladdr; struct in6_addr *addr; NMIP6Address *ip6addr; struct rtnl_route *rtnlroute; struct nl_addr *nldest, *nlgateway; struct in6_addr *dest, *gateway; gboolean defgw_set = FALSE; struct in6_addr defgw; uint32_t metric; NMIP6Route *ip6route; int i; g_return_val_if_fail (NM_IS_IP6_MANAGER (manager), NULL); g_return_val_if_fail (ifindex > 0, NULL); priv = NM_IP6_MANAGER_GET_PRIVATE (manager); device = (NMIP6Device *) g_hash_table_lookup (priv->devices, GINT_TO_POINTER (ifindex)); if (!device) { nm_log_warn (LOGD_IP6, "(%d): addrconf not started.", ifindex); return NULL; } config = nm_ip6_config_new (); if (!config) { nm_log_err (LOGD_IP6, "(%s): out of memory creating IP6 config object.", device->iface); return NULL; } /* Make sure we refill the route and address caches, otherwise we won't get * up-to-date information here since the netlink route/addr change messages * may be lagging a bit. */ nl_cache_refill (priv->nlh, priv->route_cache); nl_cache_refill (priv->nlh, priv->addr_cache); /* Add routes */ for (rtnlroute = FIRST_ROUTE (priv->route_cache); rtnlroute; rtnlroute = NEXT_ROUTE (rtnlroute)) { /* Make sure it's an IPv6 route for this device */ if (rtnl_route_get_oif (rtnlroute) != device->ifindex) continue; if (rtnl_route_get_family (rtnlroute) != AF_INET6) continue; nldest = rtnl_route_get_dst (rtnlroute); if (!nldest || nl_addr_get_family (nldest) != AF_INET6) continue; dest = nl_addr_get_binary_addr (nldest); nlgateway = rtnl_route_get_gateway (rtnlroute); if (!nlgateway || nl_addr_get_family (nlgateway) != AF_INET6) continue; gateway = nl_addr_get_binary_addr (nlgateway); if (rtnl_route_get_dst_len (rtnlroute) == 0) { /* Default gateway route; don't add to normal routes but to each address */ if (!defgw_set) { memcpy (&defgw, gateway, sizeof (defgw)); defgw_set = TRUE; } continue; } /* Also ignore link-local routes where the destination and gateway are * the same, which apparently get added by the kernel but return -EINVAL * when we try to add them via netlink. */ if (gateway && IN6_ARE_ADDR_EQUAL (dest, gateway)) continue; ip6route = nm_ip6_route_new (); nm_ip6_route_set_dest (ip6route, dest); nm_ip6_route_set_prefix (ip6route, rtnl_route_get_dst_len (rtnlroute)); nm_ip6_route_set_next_hop (ip6route, gateway); rtnl_route_get_metric(rtnlroute, 1, &metric); if (metric != UINT_MAX) nm_ip6_route_set_metric (ip6route, metric); nm_ip6_config_take_route (config, ip6route); } /* Add addresses */ for (rtnladdr = FIRST_ADDR (priv->addr_cache); rtnladdr; rtnladdr = NEXT_ADDR (rtnladdr)) { if (rtnl_addr_get_ifindex (rtnladdr) != device->ifindex) continue; nladdr = rtnl_addr_get_local (rtnladdr); if (!nladdr || nl_addr_get_family (nladdr) != AF_INET6) continue; addr = nl_addr_get_binary_addr (nladdr); ip6addr = nm_ip6_address_new (); nm_ip6_address_set_prefix (ip6addr, rtnl_addr_get_prefixlen (rtnladdr)); nm_ip6_address_set_address (ip6addr, addr); nm_ip6_config_take_address (config, ip6addr); if (defgw_set) nm_ip6_address_set_gateway (ip6addr, &defgw); } /* Add DNS servers */ if (device->rdnss_servers) { NMIP6RDNSS *rdnss = (NMIP6RDNSS *)(device->rdnss_servers->data); for (i = 0; i < device->rdnss_servers->len; i++) nm_ip6_config_add_nameserver (config, &rdnss[i].addr); } /* Add DNS domains */ if (device->dnssl_domains) { NMIP6DNSSL *dnssl = (NMIP6DNSSL *)(device->dnssl_domains->data); for (i = 0; i < device->dnssl_domains->len; i++) nm_ip6_config_add_domain (config, dnssl[i].domain); } return config; }
static void nm_ip6_device_sync_from_netlink (NMIP6Device *device, gboolean config_changed) { NMIP6Manager *manager = device->manager; NMIP6ManagerPrivate *priv = NM_IP6_MANAGER_GET_PRIVATE (manager); struct rtnl_addr *rtnladdr; struct nl_addr *nladdr; struct in6_addr *addr; CallbackInfo *info; guint dhcp_opts = IP6_DHCP_OPT_NONE; gboolean found_linklocal = FALSE, found_other = FALSE; nm_log_dbg (LOGD_IP6, "(%s): syncing with netlink (ra_flags 0x%X) (state/target '%s'/'%s')", device->iface, device->ra_flags, state_to_string (device->state), state_to_string (device->target_state)); /* Look for any IPv6 addresses the kernel may have set for the device */ for (rtnladdr = (struct rtnl_addr *) nl_cache_get_first (priv->addr_cache); rtnladdr; rtnladdr = (struct rtnl_addr *) nl_cache_get_next ((struct nl_object *) rtnladdr)) { char buf[INET6_ADDRSTRLEN]; if (rtnl_addr_get_ifindex (rtnladdr) != device->ifindex) continue; nladdr = rtnl_addr_get_local (rtnladdr); if (!nladdr || nl_addr_get_family (nladdr) != AF_INET6) continue; addr = nl_addr_get_binary_addr (nladdr); if (inet_ntop (AF_INET6, addr, buf, INET6_ADDRSTRLEN) > 0) { nm_log_dbg (LOGD_IP6, "(%s): netlink address: %s", device->iface, buf); } if (IN6_IS_ADDR_LINKLOCAL (addr)) { if (device->state == NM_IP6_DEVICE_UNCONFIGURED) device->state = NM_IP6_DEVICE_GOT_LINK_LOCAL; found_linklocal = TRUE; } else { if (device->state < NM_IP6_DEVICE_GOT_ADDRESS) device->state = NM_IP6_DEVICE_GOT_ADDRESS; found_other = TRUE; } } /* There might be a LL address hanging around on the interface from * before in the initial run, but if it goes away later, make sure we * regress from GOT_LINK_LOCAL back to UNCONFIGURED. */ if ((device->state == NM_IP6_DEVICE_GOT_LINK_LOCAL) && !found_linklocal) device->state = NM_IP6_DEVICE_UNCONFIGURED; nm_log_dbg (LOGD_IP6, "(%s): addresses synced (state %s)", device->iface, state_to_string (device->state)); /* We only care about router advertisements if we want a real IPv6 address */ if ( (device->target_state == NM_IP6_DEVICE_GOT_ADDRESS) && (device->ra_flags & IF_RA_RCVD)) { if (device->state < NM_IP6_DEVICE_GOT_ROUTER_ADVERTISEMENT) device->state = NM_IP6_DEVICE_GOT_ROUTER_ADVERTISEMENT; if (device->ra_flags & IF_RA_MANAGED) { dhcp_opts = IP6_DHCP_OPT_MANAGED; nm_log_dbg (LOGD_IP6, "router advertisement deferred to DHCPv6"); } else if (device->ra_flags & IF_RA_OTHERCONF) { dhcp_opts = IP6_DHCP_OPT_OTHERCONF; nm_log_dbg (LOGD_IP6, "router advertisement requests parallel DHCPv6"); } } if (!device->addrconf_complete) { /* Managed mode (ie DHCP only) short-circuits automatic addrconf, so * we don't bother waiting for the device's target state to be reached * when the RA requests managed mode. */ if ( (device->state >= device->target_state) || (dhcp_opts == IP6_DHCP_OPT_MANAGED)) { /* device->finish_addrconf_id may currently be a timeout * rather than an idle, so we remove the existing source. */ if (device->finish_addrconf_id) g_source_remove (device->finish_addrconf_id); nm_log_dbg (LOGD_IP6, "(%s): reached target state or Managed-mode requested (state '%s') (dhcp opts 0x%X)", device->iface, state_to_string (device->state), dhcp_opts); info = callback_info_new (device, dhcp_opts, TRUE); device->finish_addrconf_id = g_idle_add_full (G_PRIORITY_DEFAULT_IDLE, finish_addrconf, info, (GDestroyNotify) g_free); } } else if (config_changed) { if (!device->config_changed_id) { gboolean success = TRUE; /* If for some reason an RA-provided address disappeared, we need * to make sure we fail the connection as it's no longer valid. */ if ( (device->state == NM_IP6_DEVICE_GOT_ADDRESS) && (device->target_state == NM_IP6_DEVICE_GOT_ADDRESS) && !found_other) { nm_log_dbg (LOGD_IP6, "(%s): RA-provided address no longer valid", device->iface); success = FALSE; } info = callback_info_new (device, dhcp_opts, success); device->config_changed_id = g_idle_add_full (G_PRIORITY_DEFAULT_IDLE, emit_config_changed, info, (GDestroyNotify) g_free); } } }
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; }