qemu

FORK: QEMU emulator
git clone https://git.neptards.moe/neptards/qemu.git
Log | Files | Refs | Submodules | LICENSE

announce.c (6215B)


      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/cutils.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 
     18 static GData *named_timers;
     19 
     20 int64_t qemu_announce_timer_step(AnnounceTimer *timer)
     21 {
     22     int64_t step;
     23 
     24     step =  timer->params.initial +
     25             (timer->params.rounds - timer->round - 1) *
     26             timer->params.step;
     27 
     28     if (step < 0 || step > timer->params.max) {
     29         step = timer->params.max;
     30     }
     31     timer_mod(timer->tm, qemu_clock_get_ms(timer->type) + step);
     32 
     33     return step;
     34 }
     35 
     36 /*
     37  * If 'free_named' is true, then remove the timer from the list
     38  * and free the timer itself.
     39  */
     40 void qemu_announce_timer_del(AnnounceTimer *timer, bool free_named)
     41 {
     42     bool free_timer = false;
     43     if (timer->tm) {
     44         timer_free(timer->tm);
     45         timer->tm = NULL;
     46     }
     47     qapi_free_strList(timer->params.interfaces);
     48     timer->params.interfaces = NULL;
     49     if (free_named && timer->params.has_id) {
     50         AnnounceTimer *list_timer;
     51         /*
     52          * Sanity check: There should only be one timer on the list with
     53          * the id.
     54          */
     55         list_timer = g_datalist_get_data(&named_timers, timer->params.id);
     56         assert(timer == list_timer);
     57         free_timer = true;
     58         g_datalist_remove_data(&named_timers, timer->params.id);
     59     }
     60     trace_qemu_announce_timer_del(free_named, free_timer, timer->params.id);
     61     g_free(timer->params.id);
     62     timer->params.id = NULL;
     63 
     64     if (free_timer) {
     65         g_free(timer);
     66     }
     67 }
     68 
     69 /*
     70  * Under BQL/main thread
     71  * Reset the timer to the given parameters/type/notifier.
     72  */
     73 void qemu_announce_timer_reset(AnnounceTimer *timer,
     74                                AnnounceParameters *params,
     75                                QEMUClockType type,
     76                                QEMUTimerCB *cb,
     77                                void *opaque)
     78 {
     79     /*
     80      * We're under the BQL, so the current timer can't
     81      * be firing, so we should be able to delete it.
     82      */
     83     qemu_announce_timer_del(timer, false);
     84 
     85     QAPI_CLONE_MEMBERS(AnnounceParameters, &timer->params, params);
     86     timer->round = params->rounds;
     87     timer->type = type;
     88     timer->tm = timer_new_ms(type, cb, opaque);
     89 }
     90 
     91 #ifndef ETH_P_RARP
     92 #define ETH_P_RARP 0x8035
     93 #endif
     94 #define ARP_HTYPE_ETH 0x0001
     95 #define ARP_PTYPE_IP 0x0800
     96 #define ARP_OP_REQUEST_REV 0x3
     97 
     98 static int announce_self_create(uint8_t *buf,
     99                                 uint8_t *mac_addr)
    100 {
    101     /* Ethernet header. */
    102     memset(buf, 0xff, 6);         /* destination MAC addr */
    103     memcpy(buf + 6, mac_addr, 6); /* source MAC addr */
    104     *(uint16_t *)(buf + 12) = htons(ETH_P_RARP); /* ethertype */
    105 
    106     /* RARP header. */
    107     *(uint16_t *)(buf + 14) = htons(ARP_HTYPE_ETH); /* hardware addr space */
    108     *(uint16_t *)(buf + 16) = htons(ARP_PTYPE_IP); /* protocol addr space */
    109     *(buf + 18) = 6; /* hardware addr length (ethernet) */
    110     *(buf + 19) = 4; /* protocol addr length (IPv4) */
    111     *(uint16_t *)(buf + 20) = htons(ARP_OP_REQUEST_REV); /* opcode */
    112     memcpy(buf + 22, mac_addr, 6); /* source hw addr */
    113     memset(buf + 28, 0x00, 4);     /* source protocol addr */
    114     memcpy(buf + 32, mac_addr, 6); /* target hw addr */
    115     memset(buf + 38, 0x00, 4);     /* target protocol addr */
    116 
    117     /* Padding to get up to 60 bytes (ethernet min packet size, minus FCS). */
    118     memset(buf + 42, 0x00, 18);
    119 
    120     return 60; /* len (FCS will be added by hardware) */
    121 }
    122 
    123 /*
    124  * Helper to print ethernet mac address
    125  */
    126 static const char *qemu_ether_ntoa(const MACAddr *mac)
    127 {
    128     static char ret[18];
    129 
    130     snprintf(ret, sizeof(ret), "%02x:%02x:%02x:%02x:%02x:%02x",
    131              mac->a[0], mac->a[1], mac->a[2], mac->a[3], mac->a[4], mac->a[5]);
    132 
    133     return ret;
    134 }
    135 
    136 static void qemu_announce_self_iter(NICState *nic, void *opaque)
    137 {
    138     AnnounceTimer *timer = opaque;
    139     uint8_t buf[60];
    140     int len;
    141     bool skip;
    142 
    143     if (timer->params.has_interfaces) {
    144         strList *entry = timer->params.interfaces;
    145         /* Skip unless we find our name in the requested list */
    146         skip = true;
    147 
    148         while (entry) {
    149             if (!strcmp(entry->value, nic->ncs->name)) {
    150                 /* Found us */
    151                 skip = false;
    152                 break;
    153             }
    154             entry = entry->next;
    155         }
    156     } else {
    157         skip = false;
    158     }
    159 
    160     trace_qemu_announce_self_iter(timer->params.has_id ? timer->params.id : "_",
    161                                   nic->ncs->name,
    162                                   qemu_ether_ntoa(&nic->conf->macaddr), skip);
    163 
    164     if (!skip) {
    165         len = announce_self_create(buf, nic->conf->macaddr.a);
    166 
    167         qemu_send_packet_raw(qemu_get_queue(nic), buf, len);
    168 
    169         /* if the NIC provides it's own announcement support, use it as well */
    170         if (nic->ncs->info->announce) {
    171             nic->ncs->info->announce(nic->ncs);
    172         }
    173     }
    174 }
    175 static void qemu_announce_self_once(void *opaque)
    176 {
    177     AnnounceTimer *timer = (AnnounceTimer *)opaque;
    178 
    179     qemu_foreach_nic(qemu_announce_self_iter, timer);
    180 
    181     if (--timer->round) {
    182         qemu_announce_timer_step(timer);
    183     } else {
    184         qemu_announce_timer_del(timer, true);
    185     }
    186 }
    187 
    188 void qemu_announce_self(AnnounceTimer *timer, AnnounceParameters *params)
    189 {
    190     qemu_announce_timer_reset(timer, params, QEMU_CLOCK_REALTIME,
    191                               qemu_announce_self_once, timer);
    192     if (params->rounds) {
    193         qemu_announce_self_once(timer);
    194     } else {
    195         qemu_announce_timer_del(timer, true);
    196     }
    197 }
    198 
    199 void qmp_announce_self(AnnounceParameters *params, Error **errp)
    200 {
    201     AnnounceTimer *named_timer;
    202     if (!params->has_id) {
    203         params->id = g_strdup("");
    204         params->has_id = true;
    205     }
    206 
    207     named_timer = g_datalist_get_data(&named_timers, params->id);
    208 
    209     if (!named_timer) {
    210         named_timer = g_new0(AnnounceTimer, 1);
    211         g_datalist_set_data(&named_timers, params->id, named_timer);
    212     }
    213 
    214     qemu_announce_self(named_timer, params);
    215 }