int main(int argc, char *argv[]) { struct rtnl_link *link; struct nl_cache *link_cache; struct nl_sock *sk; int err; 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 ((err = create_bridge(sk, link_cache, TEST_BRIDGE_NAME)) < 0) { nl_perror(err, "Unable to allocate testbridge"); return err; } nl_cache_refill(sk, link_cache); link = rtnl_link_get_by_name(link_cache, TEST_BRIDGE_NAME); struct rtnl_link *ltap = rtnl_link_get_by_name(link_cache, TEST_INTERFACE_NAME); if (!ltap) { fprintf(stderr, "You should create a tap interface before lunch this test (# tunctl -t %s)\n", TEST_INTERFACE_NAME); return -1; } if ((err = rtnl_link_enslave(sk, link, ltap)) < 0) { nl_perror(err, "Unable to enslave interface to his bridge\n"); return err; } if(rtnl_link_is_bridge(link) == 0) { fprintf(stderr, "Link is not a bridge\n"); return -2; } if(rtnl_link_get_master(ltap) <= 0) { fprintf(stderr, "Interface is not attached to a bridge\n"); return -3; } rtnl_link_put(ltap); rtnl_link_put(link); nl_cache_free(link_cache); nl_socket_free(sk); return 0; }
int sysnet_interface_set_mtu(VPNInterface *i, unsigned int mtu) { int err; struct nl_cache *link_cache; struct nl_sock *sock; struct rtnl_link *link; struct rtnl_link *new_link; sock = nl_socket_alloc(); nl_connect(sock, NETLINK_ROUTE); rtnl_link_alloc_cache(sock, AF_UNSPEC, &link_cache); link = rtnl_link_get_by_name(link_cache, i->name); new_link = rtnl_link_alloc(); if (!link) { tox_trace(i->context->tox, "can't find link \"%s\"", i->name); return -1; } rtnl_link_set_mtu(new_link, mtu); if ((err = rtnl_link_change(sock, link, new_link, 0)) < 0) { tox_trace(i->context->tox, "unable to change link \"%s\" flags: %s", rtnl_link_get_name(link), nl_geterror(err)); } rtnl_link_put(link); rtnl_link_put(new_link); nl_cache_free(link_cache); nl_socket_free(sock); return 0; }
int main(int argc, char *argv[]) { struct nl_cache *link_cache; struct rtnl_link *link, *link2; struct nl_sock *sk; uint32_t tb_id; int err; sk = nl_socket_alloc(); if ((err = nl_connect(sk, NETLINK_ROUTE)) < 0) { nl_perror(err, "Unable to connect socket"); return err; } if (!(link = rtnl_link_vrf_alloc())) { fprintf(stderr, "Unable to allocate link"); return -1; } rtnl_link_set_name(link, "vrf-red"); if ((err = rtnl_link_vrf_set_tableid(link, 10)) < 0) { nl_perror(err, "Unable to set VRF table id"); return err; } if ((err = rtnl_link_add(sk, link, NLM_F_CREATE)) < 0) { nl_perror(err, "Unable to add link"); return err; } if ((err = rtnl_link_alloc_cache(sk, AF_UNSPEC, &link_cache)) < 0) { nl_perror(err, "Unable to allocate cache"); return err; } if (!(link2 = rtnl_link_get_by_name(link_cache, "vrf-red"))) { fprintf(stderr, "Unable to lookup vrf-red"); return -1; } if ((err = rtnl_link_vrf_get_tableid(link2, &tb_id)) < 0) { nl_perror(err, "Unable to get VRF table id"); return err; } if (tb_id != 10) { fprintf(stderr, "Mismatch with VRF table id\n"); } rtnl_link_put(link); nl_close(sk); return 0; }
/** * @ingroup cli * @defgroup cli_tc Traffic Control * @{ */ void nl_cli_tc_parse_dev(struct rtnl_tc *tc, struct nl_cache *link_cache, char *name) { struct rtnl_link *link; link = rtnl_link_get_by_name(link_cache, name); if (!link) nl_cli_fatal(ENOENT, "Link \"%s\" does not exist.", name); rtnl_tc_set_link(tc, link); rtnl_link_put(link); }
int netem_set_params(const char *iface, struct netem_params *params) { struct rtnl_link *link; struct rtnl_qdisc *qdisc; int err; pthread_mutex_lock(&nl_sock_mutex); /* filter link by name */ if ((link = rtnl_link_get_by_name(link_cache, iface)) == NULL) { fprintf(stderr, "unknown interface/link name.\n"); pthread_mutex_unlock(&nl_sock_mutex); return -1; } if (!(qdisc = rtnl_qdisc_alloc())) { /* OOM error */ fprintf(stderr, "couldn't alloc qdisc\n"); pthread_mutex_unlock(&nl_sock_mutex); return -1; } rtnl_tc_set_link(TC_CAST(qdisc), link); rtnl_tc_set_parent(TC_CAST(qdisc), TC_H_ROOT); rtnl_tc_set_kind(TC_CAST(qdisc), "netem"); rtnl_netem_set_delay(qdisc, params->delay * 1000); /* expects microseconds */ rtnl_netem_set_jitter(qdisc, params->jitter * 1000); /* params->loss is given in 10ths of a percent */ rtnl_netem_set_loss(qdisc, (params->loss * (UINT_MAX / 1000))); /* Submit request to kernel and wait for response */ err = rtnl_qdisc_add(sock, qdisc, NLM_F_CREATE | NLM_F_REPLACE); /* Return the qdisc object to free memory resources */ rtnl_qdisc_put(qdisc); if (err < 0) { fprintf(stderr, "Unable to add qdisc: %s\n", nl_geterror(err)); pthread_mutex_unlock(&nl_sock_mutex); return err; } if ((err = nl_cache_refill(sock, link_cache)) < 0) { fprintf(stderr, "Unable to resync link cache: %s\n", nl_geterror(err)); pthread_mutex_unlock(&nl_sock_mutex); return -1; } pthread_mutex_unlock(&nl_sock_mutex); return 0; }
int vlan_rem(const char *if_name) { int ret = -1; struct nl_sock *handle = NULL; struct nl_cache *cache = NULL; struct rtnl_link *rlink = NULL; wpa_printf(MSG_DEBUG, "VLAN: vlan_rem(if_name=%s)", if_name); handle = nl_socket_alloc(); if (!handle) { wpa_printf(MSG_ERROR, "VLAN: failed to open netlink socket"); goto vlan_rem_error; } if (nl_connect(handle, NETLINK_ROUTE) < 0) { wpa_printf(MSG_ERROR, "VLAN: failed to connect to netlink"); goto vlan_rem_error; } if (rtnl_link_alloc_cache(handle, AF_UNSPEC, &cache) < 0) { cache = NULL; wpa_printf(MSG_ERROR, "VLAN: failed to alloc cache"); goto vlan_rem_error; } if (!(rlink = rtnl_link_get_by_name(cache, if_name))) { /* link does not exist */ wpa_printf(MSG_ERROR, "VLAN: interface %s does not exists", if_name); goto vlan_rem_error; } if (rtnl_link_delete(handle, rlink) < 0) { wpa_printf(MSG_ERROR, "VLAN: failed to remove link %s", if_name); goto vlan_rem_error; } ret = 0; vlan_rem_error: if (rlink) rtnl_link_put(rlink); if (cache) nl_cache_free(cache); if (handle) nl_socket_free(handle); return ret; }
static J4statusNlSection * _j4status_nl_section_new(J4statusPluginContext *context, J4statusCoreInterface *core, const gchar *interface) { struct rtnl_link *link; link = rtnl_link_get_by_name(context->link_cache, interface); if ( link == NULL ) { g_warning("Couldn't get interface %s", interface); return NULL; } const gchar *name = NULL; switch ( rtnl_link_get_arptype(link) ) { case ARPHRD_ETHER: name = "nl-ether"; break; case ARPHRD_IEEE80211: name = "nl-802.11"; break; default: g_warning("Interface %s has an unsupported type", interface); rtnl_link_put(link); return NULL; } J4statusNlSection *self; self = g_new0(J4statusNlSection, 1); self->context = context; self->ifindex = rtnl_link_get_ifindex(link); self->link = link; self->section = j4status_section_new(core); j4status_section_set_name(self->section, name); j4status_section_set_instance(self->section, interface); j4status_section_set_label(self->section, interface); if ( ! j4status_section_insert(self->section) ) { _j4status_nl_section_free(self); return NULL; } _j4status_nl_section_update(self); return self; }
char *utils_get_mac_addr(char *interface) { int buflen = 20; char *buf = NULL; struct nl_handle *nlh = NULL; struct nl_cache *cache = NULL; struct rtnl_link *link = NULL; struct nl_addr *addr = NULL; if (zstr(interface)) { return NULL; } if (init_handle(&nlh) != 0) { return NULL; } if ((cache = rtnl_link_alloc_cache(nlh)) == NULL) { return NULL; } if ((link = rtnl_link_get_by_name(cache, interface)) == NULL) { goto mac2str_error2; } if ((addr = rtnl_link_get_addr(link)) == NULL) { goto mac2str_error3; } if ((buf = calloc(sizeof(char *), buflen)) == NULL) { goto mac2str_error4; } buf = nl_addr2str(addr, buf, buflen); mac2str_error4: nl_addr_destroy(addr); mac2str_error3: rtnl_link_put(link); mac2str_error2: nl_close(nlh); nl_handle_destroy(nlh); return buf; }
/* * Given an interface name (e.g., eth0), return the MAC address in human * readable format (e.g., 00:11:52:12:D9:A0). Return NULL for no match. */ char *iface_mac2str(char *ifname) { int buflen = 20; char *buf = NULL; struct nl_handle *handle = NULL; struct nl_cache *cache = NULL; struct rtnl_link *link = NULL; struct nl_addr *addr = NULL; if (ifname == NULL) { return NULL; } if ((cache = _iface_get_link_cache(&handle)) == NULL) { return NULL; } if ((link = rtnl_link_get_by_name(cache, ifname)) == NULL) { goto mac2str_error2; } if ((addr = rtnl_link_get_addr(link)) == NULL) { goto mac2str_error3; } if ((buf = calloc(sizeof(char *), buflen)) == NULL) { goto mac2str_error4; } if ((buf = nl_addr2str(addr, buf, buflen)) != NULL) { char *oldbuf = buf; buf = g_ascii_strup(buf, -1); free(oldbuf); } mac2str_error4: nl_addr_destroy(addr); mac2str_error3: rtnl_link_put(link); mac2str_error2: nl_close(handle); nl_handle_destroy(handle); return buf; }
/* * Set the MTU on the specified device. */ int iface_set_interface_mtu(char *ifname, int mtu) { int ret = 0; struct nl_handle *handle = NULL; struct nl_cache *cache = NULL; struct rtnl_link *link = NULL; struct rtnl_link *request = NULL; if (ifname == NULL) { return -1; } if (mtu <= 0) { return -2; } if ((cache = _iface_get_link_cache(&handle)) == NULL) { return -3; } if ((link = rtnl_link_get_by_name(cache, ifname)) == NULL) { ret = -4; goto ifacemtu_error1; } request = rtnl_link_alloc(); rtnl_link_set_mtu(request, mtu); if (rtnl_link_change(handle, link, request, 0)) { ret = -5; goto ifacemtu_error2; } ifacemtu_error2: rtnl_link_put(link); ifacemtu_error1: nl_close(handle); nl_handle_destroy(handle); return ret; }
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; }
// Returns the netlink link object associated with a given link by its // name. Returns None if the link is not found. inline Result<Netlink<struct rtnl_link>> get(const std::string& link) { Try<Netlink<struct nl_sock>> socket = routing::socket(); if (socket.isError()) { return Error(socket.error()); } // Dump all the netlink link objects from kernel. Note that the flag // AF_UNSPEC means all available families. struct nl_cache* c = NULL; int error = rtnl_link_alloc_cache(socket.get().get(), AF_UNSPEC, &c); if (error != 0) { return Error(nl_geterror(error)); } Netlink<struct nl_cache> cache(c); struct rtnl_link* l = rtnl_link_get_by_name(cache.get(), link.c_str()); if (l == NULL) { return None(); } return Netlink<struct rtnl_link>(l); }
void LinuxPlatformBackend::update (const QStringList& devices) { if (!LinkCache_) return; nl_cache_refill (Rtsock_, LinkCache_); for (const auto& devName : devices) { auto link = rtnl_link_get_by_name (LinkCache_, devName.toLocal8Bit ().constData ()); if (!link) { qWarning () << Q_FUNC_INFO << "no link for device" << devName; continue; } auto& info = DevInfos_ [devName]; info.Traffic_.Down_ = rtnl_link_get_stat (link, RTNL_LINK_RX_BYTES); info.Traffic_.Up_ = rtnl_link_get_stat (link, RTNL_LINK_TX_BYTES); } }
int configure_loopback_interface() { struct nl_sock *sock = NULL; struct rtnl_addr *addr = NULL; struct nl_addr* lo_addr = NULL; struct nl_cache *cache = NULL; struct rtnl_link *link = NULL, *link2 = NULL; int err, nlflags = NLM_F_CREATE, ret = 0; if(!want_cap(CAP_NET_ADMIN)) { errWarn("Cannot set the CAP_NET_ADMIN effective capability"); return -1; } sock = nl_socket_alloc(); if(sock == NULL) { errWarn("nl_socket_alloc"); return -1; } if((err = nl_connect(sock, NETLINK_ROUTE)) < 0) { fprintf(stderr, "Unable to connect to netlink: %s\n", nl_geterror(err)); ret = -1; goto out2; } if(rtnl_link_alloc_cache(sock, AF_UNSPEC, &cache) < 0) { ret = -1; goto out; } link = rtnl_link_get_by_name(cache, "lo"); if (link == NULL) { ret = -1; goto out; } addr = rtnl_addr_alloc(); if(addr == NULL) { ret = -1; goto out; } rtnl_addr_set_link(addr, link); rtnl_addr_set_family(addr, AF_INET); if((err = nl_addr_parse("127.0.0.1/8", AF_INET, &lo_addr)) < 0) { fprintf(stderr, "Unable to parse address: %s\n", nl_geterror(err)); ret = -1; goto out; } if((err = rtnl_addr_set_local(addr, lo_addr)) < 0) { fprintf(stderr, "Unable to set address: %s\n", nl_geterror(err)); ret = -1; goto out; } nl_addr_put(lo_addr); lo_addr = NULL; if ((err = rtnl_addr_add(sock, addr, nlflags)) < 0) { fprintf(stderr, "Unable to add address: %s\n", nl_geterror(err)); ret = -1; goto out; } rtnl_addr_set_family(addr, AF_INET6); if((err = nl_addr_parse("::1/128", AF_INET6, &lo_addr)) < 0) { fprintf(stderr, "Unable to parse address: %s\n", nl_geterror(err)); ret = -1; goto out; } if((err = rtnl_addr_set_local(addr, lo_addr)) < 0) { fprintf(stderr, "Unable to set address: %s\n", nl_geterror(err)); ret = -1; goto out; } nl_addr_put(lo_addr); lo_addr = NULL; if ((err = rtnl_addr_add(sock, addr, nlflags)) < 0) { fprintf(stderr, "Unable to add address: %s\n", nl_geterror(err)); ret = -1; goto out; } link2 = rtnl_link_alloc(); if(link2 == NULL) { ret = -1; goto out; } rtnl_link_set_flags(link2, IFF_UP); if((err = rtnl_link_change(sock, link, link2, 0)) < 0) { fprintf(stderr, "Unable to change link: %s\n", nl_geterror(err)); ret = -1; goto out; } out: if(lo_addr!=NULL) nl_addr_put(lo_addr); if(link2!=NULL) rtnl_link_put(link2); if(link!=NULL) rtnl_link_put(link); if(cache!=NULL) nl_cache_put(cache); if(addr!=NULL) rtnl_addr_put(addr); nl_close(sock); out2: nl_socket_free(sock); drop_caps(); return ret; }
int main(void) { struct nl_sock *sock; struct rtnl_link *link; uint32_t ht, htlink, htid, direction; char chashlink[16]=""; int err; struct nl_cache *link_cache; struct rtnl_act *act, *act2; uint32_t i; if (!(sock = nl_socket_alloc())) { printf("Unable to allocate netlink socket\n"); exit(1); } if ((err = nl_connect(sock, NETLINK_ROUTE)) < 0 ) { printf("Nu s-a putut conecta la NETLINK!\n"); nl_socket_free(sock); exit(1); } if ((err = rtnl_link_alloc_cache(sock, AF_UNSPEC, &link_cache)) < 0) { printf("Unable to allocate link cache: %s\n", nl_geterror(err)); nl_socket_free(sock); exit(1); } /* lookup interface index of eth0 */ if (!(link = rtnl_link_get_by_name(link_cache, "eth0"))) { /* error */ printf("Interface not found\n"); nl_socket_free(sock); exit(1); } err=qdisc_add_ingress(sock, link); //printf("Add main hash table\n"); /* create u32 first hash filter table * */ /* formula calcul handle: * uint32_t handle = (htid << 20) | (hash << 12) | nodeid; */ /* * Upper limit of number of hash tables: 4096 (0xFFF) * Number of hashes in a table: 256 values (0xFF) * */ /* using 256 values for hash table * each entry in hash table match a byte from IP address specified later by a hash key */ for (i = 1; i <= 0xf; i++) u32_add_ht(sock, link, 1, i, 256); /* * attach a u32 filter to the first hash * that redirects all traffic and make a hash key * from the fist byte of the IP address * */ //divisor=0x0; // unused here //handle = 0x0; // unused here //hash = 0x0; // unused here //htid = 0x0; // unused here //nodeid = 0x0; // unused here // direction = 12 -> source IP // direction = 16 -> destination IP direction = 16; /* * which hash table will use * in our case is hash table no 1 defined previous * * There are 2 posibilities to set the the hash table: * 1. Using function get_u32_handle and sent a string in * format 10: where 10 is number of the hash table * 2. Create your own value in format: 0xa00000 * */ strcpy(chashlink, "1:"); //printf("Hash Link: %s\n", chashlink); //chashlink=malloc(sizeof(char) * htlink = 0x0; // is used by get_u32_handle to return the correct value of hash table (link) if(get_u32_handle(&htlink, chashlink)) { printf ("Illegal \"link\""); nl_socket_free(sock); exit(1); } //printf ("hash link : 0x%X\n", htlink); //printf ("hash link test : %u\n", (htlink && TC_U32_NODE(htlink))); if (htlink && TC_U32_NODE(htlink)) { printf("\"link\" must be a hash table.\n"); nl_socket_free(sock); exit(1); } /* the hash mask will hit the hash table (link) no 1: in our case */ /* set the hash key mask */ //hashmask = 0xFF000000UL; // the mask that is used to match the hash in specific table, in our case for example 1:a with mean the first byte which is 10 in hash table 1 /* Here we add a hash filter which match the first byte (see the hashmask value) * of the source IP (offset 12 in the packet header) * You can use also offset 16 to match the destination IP */ /* * Also we need a filter to match our rule * This mean that we will put a 0.0.0.0/0 filter in our first rule * that match the offset 12 (source IP) * Also you can put offset 16 to match the destination IP */ u32_add_filter_on_ht_with_hashmask(sock, link, 1, 0x0, 0x0, direction, 0, 0, htlink, 0xff000000, direction, NULL, NULL); /* * For each first byte that we need to match we will create a new hash table * For example: you have those clases: 10.0.0.0/24 and 172.16.0.0/23 * For byte 10 and byte 172 will create a separate hash table that will match the second * byte from each class. * */ /* * Now we will create other filter under (ATENTION) our first hash table (link) 1: * Previous rule redirects the trafic according the hash mask to hash table (link) no 1: * Here we will match the hash tables from 1:0 to 1:ff. Under each hash table we will attach * other rules that matches next byte from IP source/destination IP and we will repeat the * previous steps. * */ act = rtnl_act_alloc(); if (!act) { printf("rtnl_act_alloc() returns %p\n", act); return -1; } rtnl_tc_set_kind(TC_CAST(act), "skbedit"); rtnl_skbedit_set_queue_mapping(act, 4); rtnl_skbedit_set_action(act, TC_ACT_PIPE); act2 = rtnl_act_alloc(); if (!act2) { printf("rtnl_act_alloc() returns %p\n", act2); return -1; } rtnl_tc_set_kind(TC_CAST(act2), "mirred"); rtnl_mirred_set_action(act2, TCA_EGRESS_REDIR); rtnl_mirred_set_policy(act2, TC_ACT_STOLEN); rtnl_mirred_set_ifindex(act2, rtnl_link_name2i(link_cache, "eth1")); // /8 check // 10.0.0.0/8 ht=get_u32_parse_handle("1:a:"); htid = (ht&0xFFFFF000); htlink=get_u32_parse_handle("2:"); u32_add_filter_on_ht_with_hashmask(sock, link, 1, 0x0a000000, 0xff000000, direction, 0, htid, htlink, 0x00ff0000, direction, act, act2); rtnl_act_put(act); nl_socket_free(sock); return 0; }
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 netem_get_params(char *iface, struct netem_params *params) { struct rtnl_link *link; struct rtnl_qdisc *filter_qdisc; struct rtnl_qdisc *found_qdisc = NULL; int err; int delay, jitter, loss; pthread_mutex_lock(&nl_sock_mutex); if ((err = nl_cache_refill(sock, link_cache)) < 0) { fprintf(stderr, "Unable to resync link cache: %s\n", nl_geterror(err)); goto cleanup; } if ((err = nl_cache_refill(sock, qdisc_cache)) < 0) { fprintf(stderr, "Unable to resync link cache: %s\n", nl_geterror(err)); goto cleanup; } /* filter link by name */ if ((link = rtnl_link_get_by_name(link_cache, iface)) == NULL) { fprintf(stderr, "unknown interface/link name.\n"); goto cleanup; } if (!(filter_qdisc = rtnl_qdisc_alloc())) { /* OOM error */ fprintf(stderr, "couldn't alloc qdisc\n"); goto cleanup_link; } rtnl_tc_set_link(TC_CAST(filter_qdisc), link); rtnl_tc_set_parent(TC_CAST(filter_qdisc), TC_H_ROOT); rtnl_tc_set_kind(TC_CAST(filter_qdisc), "netem"); found_qdisc = (struct rtnl_qdisc *)nl_cache_find( qdisc_cache, OBJ_CAST(filter_qdisc)); if (!found_qdisc) { /* The iface probably doesn't have a netem qdisc at startup. */ goto cleanup_filter_qdisc; } if (0 > (delay = rtnl_netem_get_delay(found_qdisc))) { fprintf(stderr, "couldn't get delay for iface: %s\n", iface); goto cleanup_qdisc; } params->delay = (double)delay / 1000; if (0 > (jitter = rtnl_netem_get_jitter(found_qdisc))) { fprintf(stderr, "couldn't get jitter for iface: %s\n", iface); goto cleanup_qdisc; } params->jitter = (double)jitter / 1000; if (0 > (loss = rtnl_netem_get_loss(found_qdisc))) { fprintf(stderr, "couldn't get loss for iface: %s\n", iface); goto cleanup_qdisc; } /* loss is specified in 10ths of a percent, ie. 1 ==> 0.1% */ params->loss = (int)(loss / (UINT_MAX / 1000)); rtnl_qdisc_put(found_qdisc); rtnl_qdisc_put(filter_qdisc); rtnl_link_put(link); pthread_mutex_unlock(&nl_sock_mutex); return 0; cleanup_qdisc: rtnl_qdisc_put(found_qdisc); cleanup_filter_qdisc: rtnl_qdisc_put(filter_qdisc); cleanup_link: rtnl_link_put(link); cleanup: pthread_mutex_unlock(&nl_sock_mutex); return -1; }
static int port_stats_iterator(struct nl_msg *msg, void *arg) { of_list_port_stats_entry_t *list = arg; struct nlmsghdr *nlh = nlmsg_hdr(msg); struct nlattr *attrs[OVS_VPORT_ATTR_MAX+1]; if (genlmsg_parse(nlh, sizeof(struct ovs_header), attrs, OVS_VPORT_ATTR_MAX, NULL) < 0) { abort(); } assert(attrs[OVS_VPORT_ATTR_PORT_NO]); assert(attrs[OVS_VPORT_ATTR_STATS]); uint32_t port_no = nla_get_u32(attrs[OVS_VPORT_ATTR_PORT_NO]); char *ifname = nla_get_string(attrs[OVS_VPORT_ATTR_NAME]); uint32_t vport_type = nla_get_u32(attrs[OVS_VPORT_ATTR_TYPE]); struct ovs_vport_stats *port_stats = nla_data(attrs[OVS_VPORT_ATTR_STATS]); of_port_stats_entry_t entry[1]; of_port_stats_entry_init(entry, list->version, -1, 1); if (of_list_port_stats_entry_append_bind(list, entry) < 0) { /* TODO needs fix in indigo core */ LOG_ERROR("too many port stats replies"); return NL_STOP; } of_port_stats_entry_port_no_set(entry, port_no); struct rtnl_link *link; if ((vport_type == OVS_VPORT_TYPE_NETDEV || vport_type == OVS_VPORT_TYPE_INTERNAL) && (link = rtnl_link_get_by_name(link_cache, ifname))) { /* Get interface stats from NETLINK_ROUTE */ of_port_stats_entry_rx_packets_set(entry, rtnl_link_get_stat(link, RTNL_LINK_RX_PACKETS)); of_port_stats_entry_tx_packets_set(entry, rtnl_link_get_stat(link, RTNL_LINK_TX_PACKETS)); of_port_stats_entry_rx_bytes_set(entry, rtnl_link_get_stat(link, RTNL_LINK_RX_BYTES)); of_port_stats_entry_tx_bytes_set(entry, rtnl_link_get_stat(link, RTNL_LINK_TX_BYTES)); of_port_stats_entry_rx_dropped_set(entry, rtnl_link_get_stat(link, RTNL_LINK_RX_DROPPED)); of_port_stats_entry_tx_dropped_set(entry, rtnl_link_get_stat(link, RTNL_LINK_TX_DROPPED)); of_port_stats_entry_rx_errors_set(entry, rtnl_link_get_stat(link, RTNL_LINK_RX_ERRORS)); of_port_stats_entry_tx_errors_set(entry, rtnl_link_get_stat(link, RTNL_LINK_TX_ERRORS)); of_port_stats_entry_rx_frame_err_set(entry, rtnl_link_get_stat(link, RTNL_LINK_RX_FRAME_ERR)); of_port_stats_entry_rx_over_err_set(entry, rtnl_link_get_stat(link, RTNL_LINK_RX_OVER_ERR)); of_port_stats_entry_rx_crc_err_set(entry, rtnl_link_get_stat(link, RTNL_LINK_RX_CRC_ERR)); of_port_stats_entry_collisions_set(entry, rtnl_link_get_stat(link, RTNL_LINK_COLLISIONS)); rtnl_link_put(link); } else { /* Use more limited stats from the datapath */ of_port_stats_entry_rx_packets_set(entry, port_stats->rx_packets); of_port_stats_entry_tx_packets_set(entry, port_stats->tx_packets); of_port_stats_entry_rx_bytes_set(entry, port_stats->rx_bytes); of_port_stats_entry_tx_bytes_set(entry, port_stats->tx_bytes); of_port_stats_entry_rx_dropped_set(entry, port_stats->rx_dropped); of_port_stats_entry_tx_dropped_set(entry, port_stats->tx_dropped); of_port_stats_entry_rx_errors_set(entry, port_stats->rx_errors); of_port_stats_entry_tx_errors_set(entry, port_stats->tx_errors); of_port_stats_entry_rx_frame_err_set(entry, 0); of_port_stats_entry_rx_over_err_set(entry, 0); of_port_stats_entry_rx_crc_err_set(entry, 0); of_port_stats_entry_collisions_set(entry, 0); } return NL_OK; }
/* * Add a vlan interface with name 'vlan_if_name', VLAN ID 'vid' and * tagged interface 'if_name'. * * returns -1 on error * returns 1 if the interface already exists * returns 0 otherwise */ int vlan_add(const char *if_name, int vid, const char *vlan_if_name) { int ret = -1; struct nl_sock *handle = NULL; struct nl_cache *cache = NULL; struct rtnl_link *rlink = NULL; int if_idx = 0; wpa_printf(MSG_DEBUG, "VLAN: vlan_add(if_name=%s, vid=%d, " "vlan_if_name=%s)", if_name, vid, vlan_if_name); if ((os_strlen(if_name) + 1) > IFNAMSIZ) { wpa_printf(MSG_ERROR, "VLAN: Interface name too long: '%s'", if_name); return -1; } if ((os_strlen(vlan_if_name) + 1) > IFNAMSIZ) { wpa_printf(MSG_ERROR, "VLAN: Interface name too long: '%s'", vlan_if_name); return -1; } handle = nl_socket_alloc(); if (!handle) { wpa_printf(MSG_ERROR, "VLAN: failed to open netlink socket"); goto vlan_add_error; } if (nl_connect(handle, NETLINK_ROUTE) < 0) { wpa_printf(MSG_ERROR, "VLAN: failed to connect to netlink"); goto vlan_add_error; } if (rtnl_link_alloc_cache(handle, AF_UNSPEC, &cache) < 0) { cache = NULL; wpa_printf(MSG_ERROR, "VLAN: failed to alloc cache"); goto vlan_add_error; } if (!(if_idx = rtnl_link_name2i(cache, if_name))) { /* link does not exist */ wpa_printf(MSG_ERROR, "VLAN: interface %s does not exist", if_name); goto vlan_add_error; } if ((rlink = rtnl_link_get_by_name(cache, vlan_if_name))) { /* link does exist */ rtnl_link_put(rlink); rlink = NULL; wpa_printf(MSG_ERROR, "VLAN: interface %s already exists", vlan_if_name); ret = 1; goto vlan_add_error; } rlink = rtnl_link_alloc(); if (!rlink) { wpa_printf(MSG_ERROR, "VLAN: failed to allocate new link"); goto vlan_add_error; } if (rtnl_link_set_type(rlink, "vlan") < 0) { wpa_printf(MSG_ERROR, "VLAN: failed to set link type"); goto vlan_add_error; } rtnl_link_set_link(rlink, if_idx); rtnl_link_set_name(rlink, vlan_if_name); if (rtnl_link_vlan_set_id(rlink, vid) < 0) { wpa_printf(MSG_ERROR, "VLAN: failed to set link vlan id"); goto vlan_add_error; } if (rtnl_link_add(handle, rlink, NLM_F_CREATE) < 0) { wpa_printf(MSG_ERROR, "VLAN: failed to create link %s for " "vlan %d on %s (%d)", vlan_if_name, vid, if_name, if_idx); goto vlan_add_error; } ret = 0; vlan_add_error: if (rlink) rtnl_link_put(rlink); if (cache) nl_cache_free(cache); if (handle) nl_socket_free(handle); return ret; }