]> git.proxmox.com Git - mirror_qemu.git/blame - net/announce.c
Merge remote-tracking branch 'remotes/kraxel/tags/ui-20210316-pull-request' into...
[mirror_qemu.git] / net / announce.c
CommitLineData
50510ea2
DDAG
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"
7659505c 12#include "net/net.h"
50510ea2
DDAG
13#include "qapi/clone-visitor.h"
14#include "qapi/qapi-visit-net.h"
a06cd488 15#include "qapi/qapi-commands-net.h"
7659505c 16#include "trace.h"
50510ea2 17
944458b6
DDAG
18static GData *named_timers;
19
50510ea2
DDAG
20int64_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
944458b6
DDAG
36/*
37 * If 'free_named' is true, then remove the timer from the list
38 * and free the timer itself.
39 */
40void qemu_announce_timer_del(AnnounceTimer *timer, bool free_named)
50510ea2 41{
944458b6 42 bool free_timer = false;
50510ea2 43 if (timer->tm) {
50510ea2
DDAG
44 timer_free(timer->tm);
45 timer->tm = NULL;
46 }
ef2fdbfb
DDAG
47 qapi_free_strList(timer->params.interfaces);
48 timer->params.interfaces = NULL;
944458b6
DDAG
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 }
50510ea2
DDAG
67}
68
69/*
70 * Under BQL/main thread
71 * Reset the timer to the given parameters/type/notifier.
72 */
73void 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 */
944458b6 83 qemu_announce_timer_del(timer, false);
50510ea2
DDAG
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}
7659505c
DDAG
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
98static 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
123static void qemu_announce_self_iter(NICState *nic, void *opaque)
124{
ef2fdbfb 125 AnnounceTimer *timer = opaque;
7659505c
DDAG
126 uint8_t buf[60];
127 int len;
ef2fdbfb
DDAG
128 bool skip;
129
130 if (timer->params.has_interfaces) {
131 strList *entry = timer->params.interfaces;
132 /* Skip unless we find our name in the requested list */
133 skip = true;
134
135 while (entry) {
136 if (!strcmp(entry->value, nic->ncs->name)) {
137 /* Found us */
138 skip = false;
139 break;
140 }
141 entry = entry->next;
142 }
143 } else {
144 skip = false;
145 }
146
944458b6
DDAG
147 trace_qemu_announce_self_iter(timer->params.has_id ? timer->params.id : "_",
148 nic->ncs->name,
ef2fdbfb 149 qemu_ether_ntoa(&nic->conf->macaddr), skip);
7659505c 150
ef2fdbfb
DDAG
151 if (!skip) {
152 len = announce_self_create(buf, nic->conf->macaddr.a);
7659505c 153
ef2fdbfb 154 qemu_send_packet_raw(qemu_get_queue(nic), buf, len);
44b416ad 155
ef2fdbfb
DDAG
156 /* if the NIC provides it's own announcement support, use it as well */
157 if (nic->ncs->info->announce) {
158 nic->ncs->info->announce(nic->ncs);
159 }
44b416ad 160 }
7659505c
DDAG
161}
162static void qemu_announce_self_once(void *opaque)
163{
164 AnnounceTimer *timer = (AnnounceTimer *)opaque;
165
ef2fdbfb 166 qemu_foreach_nic(qemu_announce_self_iter, timer);
7659505c
DDAG
167
168 if (--timer->round) {
169 qemu_announce_timer_step(timer);
170 } else {
944458b6 171 qemu_announce_timer_del(timer, true);
7659505c
DDAG
172 }
173}
174
175void qemu_announce_self(AnnounceTimer *timer, AnnounceParameters *params)
176{
177 qemu_announce_timer_reset(timer, params, QEMU_CLOCK_REALTIME,
178 qemu_announce_self_once, timer);
179 if (params->rounds) {
180 qemu_announce_self_once(timer);
181 } else {
944458b6 182 qemu_announce_timer_del(timer, true);
7659505c
DDAG
183 }
184}
a06cd488
DDAG
185
186void qmp_announce_self(AnnounceParameters *params, Error **errp)
187{
944458b6
DDAG
188 AnnounceTimer *named_timer;
189 if (!params->has_id) {
190 params->id = g_strdup("");
191 params->has_id = true;
192 }
193
194 named_timer = g_datalist_get_data(&named_timers, params->id);
195
196 if (!named_timer) {
197 named_timer = g_new0(AnnounceTimer, 1);
198 g_datalist_set_data(&named_timers, params->id, named_timer);
199 }
200
201 qemu_announce_self(named_timer, params);
a06cd488 202}