qemu/net/announce.c
<<
>>
Prefs
   1/*
   2 *  Self-announce
   3 *  (c) 2017-2019 Red Hat, Inc.
   4 *
   5 * This work is licensed under the terms of the GNU GPL, version 2 or later.
   6 * See the COPYING file in the top-level directory.
   7 */
   8
   9#include "qemu/osdep.h"
  10#include "qemu-common.h"
  11#include "net/announce.h"
  12#include "net/net.h"
  13#include "qapi/clone-visitor.h"
  14#include "qapi/qapi-visit-net.h"
  15#include "qapi/qapi-commands-net.h"
  16#include "trace.h"
  17
  18int64_t qemu_announce_timer_step(AnnounceTimer *timer)
  19{
  20    int64_t step;
  21
  22    step =  timer->params.initial +
  23            (timer->params.rounds - timer->round - 1) *
  24            timer->params.step;
  25
  26    if (step < 0 || step > timer->params.max) {
  27        step = timer->params.max;
  28    }
  29    timer_mod(timer->tm, qemu_clock_get_ms(timer->type) + step);
  30
  31    return step;
  32}
  33
  34void qemu_announce_timer_del(AnnounceTimer *timer)
  35{
  36    if (timer->tm) {
  37        timer_del(timer->tm);
  38        timer_free(timer->tm);
  39        timer->tm = NULL;
  40    }
  41}
  42
  43/*
  44 * Under BQL/main thread
  45 * Reset the timer to the given parameters/type/notifier.
  46 */
  47void qemu_announce_timer_reset(AnnounceTimer *timer,
  48                               AnnounceParameters *params,
  49                               QEMUClockType type,
  50                               QEMUTimerCB *cb,
  51                               void *opaque)
  52{
  53    /*
  54     * We're under the BQL, so the current timer can't
  55     * be firing, so we should be able to delete it.
  56     */
  57    qemu_announce_timer_del(timer);
  58
  59    QAPI_CLONE_MEMBERS(AnnounceParameters, &timer->params, params);
  60    timer->round = params->rounds;
  61    timer->type = type;
  62    timer->tm = timer_new_ms(type, cb, opaque);
  63}
  64
  65#ifndef ETH_P_RARP
  66#define ETH_P_RARP 0x8035
  67#endif
  68#define ARP_HTYPE_ETH 0x0001
  69#define ARP_PTYPE_IP 0x0800
  70#define ARP_OP_REQUEST_REV 0x3
  71
  72static int announce_self_create(uint8_t *buf,
  73                                uint8_t *mac_addr)
  74{
  75    /* Ethernet header. */
  76    memset(buf, 0xff, 6);         /* destination MAC addr */
  77    memcpy(buf + 6, mac_addr, 6); /* source MAC addr */
  78    *(uint16_t *)(buf + 12) = htons(ETH_P_RARP); /* ethertype */
  79
  80    /* RARP header. */
  81    *(uint16_t *)(buf + 14) = htons(ARP_HTYPE_ETH); /* hardware addr space */
  82    *(uint16_t *)(buf + 16) = htons(ARP_PTYPE_IP); /* protocol addr space */
  83    *(buf + 18) = 6; /* hardware addr length (ethernet) */
  84    *(buf + 19) = 4; /* protocol addr length (IPv4) */
  85    *(uint16_t *)(buf + 20) = htons(ARP_OP_REQUEST_REV); /* opcode */
  86    memcpy(buf + 22, mac_addr, 6); /* source hw addr */
  87    memset(buf + 28, 0x00, 4);     /* source protocol addr */
  88    memcpy(buf + 32, mac_addr, 6); /* target hw addr */
  89    memset(buf + 38, 0x00, 4);     /* target protocol addr */
  90
  91    /* Padding to get up to 60 bytes (ethernet min packet size, minus FCS). */
  92    memset(buf + 42, 0x00, 18);
  93
  94    return 60; /* len (FCS will be added by hardware) */
  95}
  96
  97static void qemu_announce_self_iter(NICState *nic, void *opaque)
  98{
  99    uint8_t buf[60];
 100    int len;
 101
 102    trace_qemu_announce_self_iter(qemu_ether_ntoa(&nic->conf->macaddr));
 103    len = announce_self_create(buf, nic->conf->macaddr.a);
 104
 105    qemu_send_packet_raw(qemu_get_queue(nic), buf, len);
 106
 107    /* if the NIC provides it's own announcement support, use it as well */
 108    if (nic->ncs->info->announce) {
 109        nic->ncs->info->announce(nic->ncs);
 110    }
 111}
 112static void qemu_announce_self_once(void *opaque)
 113{
 114    AnnounceTimer *timer = (AnnounceTimer *)opaque;
 115
 116    qemu_foreach_nic(qemu_announce_self_iter, NULL);
 117
 118    if (--timer->round) {
 119        qemu_announce_timer_step(timer);
 120    } else {
 121        qemu_announce_timer_del(timer);
 122    }
 123}
 124
 125void qemu_announce_self(AnnounceTimer *timer, AnnounceParameters *params)
 126{
 127    qemu_announce_timer_reset(timer, params, QEMU_CLOCK_REALTIME,
 128                              qemu_announce_self_once, timer);
 129    if (params->rounds) {
 130        qemu_announce_self_once(timer);
 131    } else {
 132        qemu_announce_timer_del(timer);
 133    }
 134}
 135
 136void qmp_announce_self(AnnounceParameters *params, Error **errp)
 137{
 138    static AnnounceTimer announce_timer;
 139    qemu_announce_self(&announce_timer, params);
 140}
 141