3 * (c) 2017-2019 Red Hat, Inc.
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.
9 #include "qemu/osdep.h"
10 #include "qemu-common.h"
11 #include "net/announce.h"
13 #include "qapi/clone-visitor.h"
14 #include "qapi/qapi-visit-net.h"
15 #include "qapi/qapi-commands-net.h"
18 static GData
*named_timers
;
20 int64_t qemu_announce_timer_step(AnnounceTimer
*timer
)
24 step
= timer
->params
.initial
+
25 (timer
->params
.rounds
- timer
->round
- 1) *
28 if (step
< 0 || step
> timer
->params
.max
) {
29 step
= timer
->params
.max
;
31 timer_mod(timer
->tm
, qemu_clock_get_ms(timer
->type
) + step
);
37 * If 'free_named' is true, then remove the timer from the list
38 * and free the timer itself.
40 void qemu_announce_timer_del(AnnounceTimer
*timer
, bool free_named
)
42 bool free_timer
= false;
45 timer_free(timer
->tm
);
48 qapi_free_strList(timer
->params
.interfaces
);
49 timer
->params
.interfaces
= NULL
;
50 if (free_named
&& timer
->params
.has_id
) {
51 AnnounceTimer
*list_timer
;
53 * Sanity check: There should only be one timer on the list with
56 list_timer
= g_datalist_get_data(&named_timers
, timer
->params
.id
);
57 assert(timer
== list_timer
);
59 g_datalist_remove_data(&named_timers
, timer
->params
.id
);
61 trace_qemu_announce_timer_del(free_named
, free_timer
, timer
->params
.id
);
62 g_free(timer
->params
.id
);
63 timer
->params
.id
= NULL
;
71 * Under BQL/main thread
72 * Reset the timer to the given parameters/type/notifier.
74 void qemu_announce_timer_reset(AnnounceTimer
*timer
,
75 AnnounceParameters
*params
,
81 * We're under the BQL, so the current timer can't
82 * be firing, so we should be able to delete it.
84 qemu_announce_timer_del(timer
, false);
86 QAPI_CLONE_MEMBERS(AnnounceParameters
, &timer
->params
, params
);
87 timer
->round
= params
->rounds
;
89 timer
->tm
= timer_new_ms(type
, cb
, opaque
);
93 #define ETH_P_RARP 0x8035
95 #define ARP_HTYPE_ETH 0x0001
96 #define ARP_PTYPE_IP 0x0800
97 #define ARP_OP_REQUEST_REV 0x3
99 static int announce_self_create(uint8_t *buf
,
102 /* Ethernet header. */
103 memset(buf
, 0xff, 6); /* destination MAC addr */
104 memcpy(buf
+ 6, mac_addr
, 6); /* source MAC addr */
105 *(uint16_t *)(buf
+ 12) = htons(ETH_P_RARP
); /* ethertype */
108 *(uint16_t *)(buf
+ 14) = htons(ARP_HTYPE_ETH
); /* hardware addr space */
109 *(uint16_t *)(buf
+ 16) = htons(ARP_PTYPE_IP
); /* protocol addr space */
110 *(buf
+ 18) = 6; /* hardware addr length (ethernet) */
111 *(buf
+ 19) = 4; /* protocol addr length (IPv4) */
112 *(uint16_t *)(buf
+ 20) = htons(ARP_OP_REQUEST_REV
); /* opcode */
113 memcpy(buf
+ 22, mac_addr
, 6); /* source hw addr */
114 memset(buf
+ 28, 0x00, 4); /* source protocol addr */
115 memcpy(buf
+ 32, mac_addr
, 6); /* target hw addr */
116 memset(buf
+ 38, 0x00, 4); /* target protocol addr */
118 /* Padding to get up to 60 bytes (ethernet min packet size, minus FCS). */
119 memset(buf
+ 42, 0x00, 18);
121 return 60; /* len (FCS will be added by hardware) */
124 static void qemu_announce_self_iter(NICState
*nic
, void *opaque
)
126 AnnounceTimer
*timer
= opaque
;
131 if (timer
->params
.has_interfaces
) {
132 strList
*entry
= timer
->params
.interfaces
;
133 /* Skip unless we find our name in the requested list */
137 if (!strcmp(entry
->value
, nic
->ncs
->name
)) {
148 trace_qemu_announce_self_iter(timer
->params
.has_id
? timer
->params
.id
: "_",
150 qemu_ether_ntoa(&nic
->conf
->macaddr
), skip
);
153 len
= announce_self_create(buf
, nic
->conf
->macaddr
.a
);
155 qemu_send_packet_raw(qemu_get_queue(nic
), buf
, len
);
157 /* if the NIC provides it's own announcement support, use it as well */
158 if (nic
->ncs
->info
->announce
) {
159 nic
->ncs
->info
->announce(nic
->ncs
);
163 static void qemu_announce_self_once(void *opaque
)
165 AnnounceTimer
*timer
= (AnnounceTimer
*)opaque
;
167 qemu_foreach_nic(qemu_announce_self_iter
, timer
);
169 if (--timer
->round
) {
170 qemu_announce_timer_step(timer
);
172 qemu_announce_timer_del(timer
, true);
176 void qemu_announce_self(AnnounceTimer
*timer
, AnnounceParameters
*params
)
178 qemu_announce_timer_reset(timer
, params
, QEMU_CLOCK_REALTIME
,
179 qemu_announce_self_once
, timer
);
180 if (params
->rounds
) {
181 qemu_announce_self_once(timer
);
183 qemu_announce_timer_del(timer
, true);
187 void qmp_announce_self(AnnounceParameters
*params
, Error
**errp
)
189 AnnounceTimer
*named_timer
;
190 if (!params
->has_id
) {
191 params
->id
= g_strdup("");
192 params
->has_id
= true;
195 named_timer
= g_datalist_get_data(&named_timers
, params
->id
);
198 named_timer
= g_new0(AnnounceTimer
, 1);
199 g_datalist_set_data(&named_timers
, params
->id
, named_timer
);
202 qemu_announce_self(named_timer
, params
);