7b713b81c27277f37420c121f2c9eeb10646ff5aTom Gundersen/***
7b713b81c27277f37420c121f2c9eeb10646ff5aTom Gundersen This file is part of systemd.
7b713b81c27277f37420c121f2c9eeb10646ff5aTom Gundersen
7b713b81c27277f37420c121f2c9eeb10646ff5aTom Gundersen Copyright (C) 2014 Tom Gundersen <teg@jklm.no>
7b713b81c27277f37420c121f2c9eeb10646ff5aTom Gundersen
7b713b81c27277f37420c121f2c9eeb10646ff5aTom Gundersen systemd is free software; you can redistribute it and/or modify it
7b713b81c27277f37420c121f2c9eeb10646ff5aTom Gundersen under the terms of the GNU Lesser General Public License as published by
7b713b81c27277f37420c121f2c9eeb10646ff5aTom Gundersen the Free Software Foundation; either version 2.1 of the License, or
7b713b81c27277f37420c121f2c9eeb10646ff5aTom Gundersen (at your option) any later version.
7b713b81c27277f37420c121f2c9eeb10646ff5aTom Gundersen
7b713b81c27277f37420c121f2c9eeb10646ff5aTom Gundersen systemd is distributed in the hope that it will be useful, but
7b713b81c27277f37420c121f2c9eeb10646ff5aTom Gundersen WITHOUT ANY WARRANTY; without even the implied warranty of
7b713b81c27277f37420c121f2c9eeb10646ff5aTom Gundersen MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
7b713b81c27277f37420c121f2c9eeb10646ff5aTom Gundersen Lesser General Public License for more details.
7b713b81c27277f37420c121f2c9eeb10646ff5aTom Gundersen
7b713b81c27277f37420c121f2c9eeb10646ff5aTom Gundersen You should have received a copy of the GNU Lesser General Public License
7b713b81c27277f37420c121f2c9eeb10646ff5aTom Gundersen along with systemd; If not, see <http://www.gnu.org/licenses/>.
7b713b81c27277f37420c121f2c9eeb10646ff5aTom Gundersen***/
7b713b81c27277f37420c121f2c9eeb10646ff5aTom Gundersen
7b713b81c27277f37420c121f2c9eeb10646ff5aTom Gundersen#include <errno.h>
07630cea1f3a845c09309f197ac7c4f11edd3b62Lennart Poettering#include <net/if.h>
07630cea1f3a845c09309f197ac7c4f11edd3b62Lennart Poettering#include <stdlib.h>
7b713b81c27277f37420c121f2c9eeb10646ff5aTom Gundersen#include <unistd.h>
7b713b81c27277f37420c121f2c9eeb10646ff5aTom Gundersen#include <linux/veth.h>
7b713b81c27277f37420c121f2c9eeb10646ff5aTom Gundersen
7b713b81c27277f37420c121f2c9eeb10646ff5aTom Gundersen#include "sd-event.h"
7b713b81c27277f37420c121f2c9eeb10646ff5aTom Gundersen#include "sd-ipv4ll.h"
07630cea1f3a845c09309f197ac7c4f11edd3b62Lennart Poettering#include "sd-netlink.h"
7b713b81c27277f37420c121f2c9eeb10646ff5aTom Gundersen
b5efdb8af40ea759a1ea584c1bc44ecc81dd00ceLennart Poettering#include "alloc-util.h"
7b713b81c27277f37420c121f2c9eeb10646ff5aTom Gundersen#include "in-addr-util.h"
07630cea1f3a845c09309f197ac7c4f11edd3b62Lennart Poettering#include "netlink-util.h"
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering#include "parse-util.h"
07630cea1f3a845c09309f197ac7c4f11edd3b62Lennart Poettering#include "string-util.h"
07630cea1f3a845c09309f197ac7c4f11edd3b62Lennart Poettering#include "util.h"
7b713b81c27277f37420c121f2c9eeb10646ff5aTom Gundersen
7b713b81c27277f37420c121f2c9eeb10646ff5aTom Gundersenstatic void ll_handler(sd_ipv4ll *ll, int event, void *userdata) {
7b713b81c27277f37420c121f2c9eeb10646ff5aTom Gundersen _cleanup_free_ char *address = NULL;
7b713b81c27277f37420c121f2c9eeb10646ff5aTom Gundersen struct in_addr addr = {};
7b713b81c27277f37420c121f2c9eeb10646ff5aTom Gundersen
7b713b81c27277f37420c121f2c9eeb10646ff5aTom Gundersen assert_se(ll);
7b713b81c27277f37420c121f2c9eeb10646ff5aTom Gundersen
7b713b81c27277f37420c121f2c9eeb10646ff5aTom Gundersen if (sd_ipv4ll_get_address(ll, &addr) >= 0)
7b713b81c27277f37420c121f2c9eeb10646ff5aTom Gundersen assert_se(in_addr_to_string(AF_INET, (const union in_addr_union*) &addr, &address) >= 0);
7b713b81c27277f37420c121f2c9eeb10646ff5aTom Gundersen
7b713b81c27277f37420c121f2c9eeb10646ff5aTom Gundersen switch (event) {
be19c5b5e0c0f78b8429b126936fa15856550a23David Herrmann case SD_IPV4LL_EVENT_BIND:
7b713b81c27277f37420c121f2c9eeb10646ff5aTom Gundersen log_info("bound %s", strna(address));
7b713b81c27277f37420c121f2c9eeb10646ff5aTom Gundersen break;
be19c5b5e0c0f78b8429b126936fa15856550a23David Herrmann case SD_IPV4LL_EVENT_CONFLICT:
7b713b81c27277f37420c121f2c9eeb10646ff5aTom Gundersen log_info("conflict on %s", strna(address));
7b713b81c27277f37420c121f2c9eeb10646ff5aTom Gundersen break;
be19c5b5e0c0f78b8429b126936fa15856550a23David Herrmann case SD_IPV4LL_EVENT_STOP:
7b713b81c27277f37420c121f2c9eeb10646ff5aTom Gundersen log_error("the client was stopped with address %s", strna(address));
7b713b81c27277f37420c121f2c9eeb10646ff5aTom Gundersen break;
7b713b81c27277f37420c121f2c9eeb10646ff5aTom Gundersen default:
7b713b81c27277f37420c121f2c9eeb10646ff5aTom Gundersen assert_not_reached("invalid LL event");
7b713b81c27277f37420c121f2c9eeb10646ff5aTom Gundersen }
7b713b81c27277f37420c121f2c9eeb10646ff5aTom Gundersen}
7b713b81c27277f37420c121f2c9eeb10646ff5aTom Gundersen
7b713b81c27277f37420c121f2c9eeb10646ff5aTom Gundersenstatic int client_run(int ifindex, const char *seed_str, const struct ether_addr *ha, sd_event *e) {
7b713b81c27277f37420c121f2c9eeb10646ff5aTom Gundersen sd_ipv4ll *ll;
7b713b81c27277f37420c121f2c9eeb10646ff5aTom Gundersen
7b713b81c27277f37420c121f2c9eeb10646ff5aTom Gundersen assert_se(sd_ipv4ll_new(&ll) >= 0);
7b713b81c27277f37420c121f2c9eeb10646ff5aTom Gundersen assert_se(sd_ipv4ll_attach_event(ll, e, 0) >= 0);
7b713b81c27277f37420c121f2c9eeb10646ff5aTom Gundersen
7b713b81c27277f37420c121f2c9eeb10646ff5aTom Gundersen assert_se(sd_ipv4ll_set_index(ll, ifindex) >= 0);
7b713b81c27277f37420c121f2c9eeb10646ff5aTom Gundersen assert_se(sd_ipv4ll_set_mac(ll, ha) >= 0);
7b713b81c27277f37420c121f2c9eeb10646ff5aTom Gundersen assert_se(sd_ipv4ll_set_callback(ll, ll_handler, NULL) >= 0);
7b713b81c27277f37420c121f2c9eeb10646ff5aTom Gundersen
7b713b81c27277f37420c121f2c9eeb10646ff5aTom Gundersen if (seed_str) {
7b713b81c27277f37420c121f2c9eeb10646ff5aTom Gundersen unsigned seed;
7b713b81c27277f37420c121f2c9eeb10646ff5aTom Gundersen
7b713b81c27277f37420c121f2c9eeb10646ff5aTom Gundersen assert_se(safe_atou(seed_str, &seed) >= 0);
7b713b81c27277f37420c121f2c9eeb10646ff5aTom Gundersen
7b713b81c27277f37420c121f2c9eeb10646ff5aTom Gundersen assert_se(sd_ipv4ll_set_address_seed(ll, seed) >= 0);
7b713b81c27277f37420c121f2c9eeb10646ff5aTom Gundersen }
7b713b81c27277f37420c121f2c9eeb10646ff5aTom Gundersen
7b713b81c27277f37420c121f2c9eeb10646ff5aTom Gundersen log_info("starting IPv4LL client");
7b713b81c27277f37420c121f2c9eeb10646ff5aTom Gundersen
7b713b81c27277f37420c121f2c9eeb10646ff5aTom Gundersen assert_se(sd_ipv4ll_start(ll) >= 0);
7b713b81c27277f37420c121f2c9eeb10646ff5aTom Gundersen
7b713b81c27277f37420c121f2c9eeb10646ff5aTom Gundersen assert_se(sd_event_loop(e) >= 0);
7b713b81c27277f37420c121f2c9eeb10646ff5aTom Gundersen
7b713b81c27277f37420c121f2c9eeb10646ff5aTom Gundersen assert_se(!sd_ipv4ll_unref(ll));
7b713b81c27277f37420c121f2c9eeb10646ff5aTom Gundersen
7b713b81c27277f37420c121f2c9eeb10646ff5aTom Gundersen return EXIT_SUCCESS;
7b713b81c27277f37420c121f2c9eeb10646ff5aTom Gundersen}
7b713b81c27277f37420c121f2c9eeb10646ff5aTom Gundersen
7b713b81c27277f37420c121f2c9eeb10646ff5aTom Gundersenstatic int test_ll(const char *ifname, const char *seed) {
4afd3348c7506dd1d36305b7bcb9feb8952b9d6bLennart Poettering _cleanup_(sd_event_unrefp) sd_event *e = NULL;
4afd3348c7506dd1d36305b7bcb9feb8952b9d6bLennart Poettering _cleanup_(sd_netlink_unrefp) sd_netlink *rtnl = NULL;
4afd3348c7506dd1d36305b7bcb9feb8952b9d6bLennart Poettering _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL, *reply = NULL;
7b713b81c27277f37420c121f2c9eeb10646ff5aTom Gundersen struct ether_addr ha;
7b713b81c27277f37420c121f2c9eeb10646ff5aTom Gundersen int ifindex;
7b713b81c27277f37420c121f2c9eeb10646ff5aTom Gundersen
7b713b81c27277f37420c121f2c9eeb10646ff5aTom Gundersen assert_se(sd_event_new(&e) >= 0);
7b713b81c27277f37420c121f2c9eeb10646ff5aTom Gundersen
7b713b81c27277f37420c121f2c9eeb10646ff5aTom Gundersen assert_se(sd_netlink_open(&rtnl) >= 0);
7b713b81c27277f37420c121f2c9eeb10646ff5aTom Gundersen assert_se(sd_netlink_attach_event(rtnl, e, 0) >= 0);
7b713b81c27277f37420c121f2c9eeb10646ff5aTom Gundersen
7b713b81c27277f37420c121f2c9eeb10646ff5aTom Gundersen assert_se(sd_rtnl_message_new_link(rtnl, &m, RTM_GETLINK, 0) >= 0);
7b713b81c27277f37420c121f2c9eeb10646ff5aTom Gundersen assert_se(sd_netlink_message_append_string(m, IFLA_IFNAME, ifname) >= 0);
7b713b81c27277f37420c121f2c9eeb10646ff5aTom Gundersen assert_se(sd_netlink_call(rtnl, m, 0, &reply) >= 0);
7b713b81c27277f37420c121f2c9eeb10646ff5aTom Gundersen
7b713b81c27277f37420c121f2c9eeb10646ff5aTom Gundersen assert_se(sd_rtnl_message_link_get_ifindex(reply, &ifindex) >= 0);
7b713b81c27277f37420c121f2c9eeb10646ff5aTom Gundersen assert_se(sd_netlink_message_read_ether_addr(reply, IFLA_ADDRESS, &ha) >= 0);
7b713b81c27277f37420c121f2c9eeb10646ff5aTom Gundersen
7b713b81c27277f37420c121f2c9eeb10646ff5aTom Gundersen client_run(ifindex, seed, &ha, e);
7b713b81c27277f37420c121f2c9eeb10646ff5aTom Gundersen
7b713b81c27277f37420c121f2c9eeb10646ff5aTom Gundersen return EXIT_SUCCESS;
7b713b81c27277f37420c121f2c9eeb10646ff5aTom Gundersen}
7b713b81c27277f37420c121f2c9eeb10646ff5aTom Gundersen
7b713b81c27277f37420c121f2c9eeb10646ff5aTom Gundersenint main(int argc, char *argv[]) {
7b713b81c27277f37420c121f2c9eeb10646ff5aTom Gundersen log_set_max_level(LOG_DEBUG);
7b713b81c27277f37420c121f2c9eeb10646ff5aTom Gundersen log_parse_environment();
7b713b81c27277f37420c121f2c9eeb10646ff5aTom Gundersen log_open();
7b713b81c27277f37420c121f2c9eeb10646ff5aTom Gundersen
7b713b81c27277f37420c121f2c9eeb10646ff5aTom Gundersen if (argc == 2)
7b713b81c27277f37420c121f2c9eeb10646ff5aTom Gundersen return test_ll(argv[1], NULL);
7b713b81c27277f37420c121f2c9eeb10646ff5aTom Gundersen else if (argc == 3)
7b713b81c27277f37420c121f2c9eeb10646ff5aTom Gundersen return test_ll(argv[1], argv[2]);
7b713b81c27277f37420c121f2c9eeb10646ff5aTom Gundersen else {
7b713b81c27277f37420c121f2c9eeb10646ff5aTom Gundersen log_error("This program takes one or two arguments.\n"
7b713b81c27277f37420c121f2c9eeb10646ff5aTom Gundersen "\t %s <ifname> [<seed>]", program_invocation_short_name);
7b713b81c27277f37420c121f2c9eeb10646ff5aTom Gundersen return EXIT_FAILURE;
7b713b81c27277f37420c121f2c9eeb10646ff5aTom Gundersen }
7b713b81c27277f37420c121f2c9eeb10646ff5aTom Gundersen}