]>
Commit | Line | Data |
---|---|---|
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" | |
7659505c | 15 | #include "trace.h" |
50510ea2 DDAG |
16 | |
17 | int64_t qemu_announce_timer_step(AnnounceTimer *timer) | |
18 | { | |
19 | int64_t step; | |
20 | ||
21 | step = timer->params.initial + | |
22 | (timer->params.rounds - timer->round - 1) * | |
23 | timer->params.step; | |
24 | ||
25 | if (step < 0 || step > timer->params.max) { | |
26 | step = timer->params.max; | |
27 | } | |
28 | timer_mod(timer->tm, qemu_clock_get_ms(timer->type) + step); | |
29 | ||
30 | return step; | |
31 | } | |
32 | ||
33 | void qemu_announce_timer_del(AnnounceTimer *timer) | |
34 | { | |
35 | if (timer->tm) { | |
36 | timer_del(timer->tm); | |
37 | timer_free(timer->tm); | |
38 | timer->tm = NULL; | |
39 | } | |
40 | } | |
41 | ||
42 | /* | |
43 | * Under BQL/main thread | |
44 | * Reset the timer to the given parameters/type/notifier. | |
45 | */ | |
46 | void qemu_announce_timer_reset(AnnounceTimer *timer, | |
47 | AnnounceParameters *params, | |
48 | QEMUClockType type, | |
49 | QEMUTimerCB *cb, | |
50 | void *opaque) | |
51 | { | |
52 | /* | |
53 | * We're under the BQL, so the current timer can't | |
54 | * be firing, so we should be able to delete it. | |
55 | */ | |
56 | qemu_announce_timer_del(timer); | |
57 | ||
58 | QAPI_CLONE_MEMBERS(AnnounceParameters, &timer->params, params); | |
59 | timer->round = params->rounds; | |
60 | timer->type = type; | |
61 | timer->tm = timer_new_ms(type, cb, opaque); | |
62 | } | |
7659505c DDAG |
63 | |
64 | #ifndef ETH_P_RARP | |
65 | #define ETH_P_RARP 0x8035 | |
66 | #endif | |
67 | #define ARP_HTYPE_ETH 0x0001 | |
68 | #define ARP_PTYPE_IP 0x0800 | |
69 | #define ARP_OP_REQUEST_REV 0x3 | |
70 | ||
71 | static int announce_self_create(uint8_t *buf, | |
72 | uint8_t *mac_addr) | |
73 | { | |
74 | /* Ethernet header. */ | |
75 | memset(buf, 0xff, 6); /* destination MAC addr */ | |
76 | memcpy(buf + 6, mac_addr, 6); /* source MAC addr */ | |
77 | *(uint16_t *)(buf + 12) = htons(ETH_P_RARP); /* ethertype */ | |
78 | ||
79 | /* RARP header. */ | |
80 | *(uint16_t *)(buf + 14) = htons(ARP_HTYPE_ETH); /* hardware addr space */ | |
81 | *(uint16_t *)(buf + 16) = htons(ARP_PTYPE_IP); /* protocol addr space */ | |
82 | *(buf + 18) = 6; /* hardware addr length (ethernet) */ | |
83 | *(buf + 19) = 4; /* protocol addr length (IPv4) */ | |
84 | *(uint16_t *)(buf + 20) = htons(ARP_OP_REQUEST_REV); /* opcode */ | |
85 | memcpy(buf + 22, mac_addr, 6); /* source hw addr */ | |
86 | memset(buf + 28, 0x00, 4); /* source protocol addr */ | |
87 | memcpy(buf + 32, mac_addr, 6); /* target hw addr */ | |
88 | memset(buf + 38, 0x00, 4); /* target protocol addr */ | |
89 | ||
90 | /* Padding to get up to 60 bytes (ethernet min packet size, minus FCS). */ | |
91 | memset(buf + 42, 0x00, 18); | |
92 | ||
93 | return 60; /* len (FCS will be added by hardware) */ | |
94 | } | |
95 | ||
96 | static void qemu_announce_self_iter(NICState *nic, void *opaque) | |
97 | { | |
98 | uint8_t buf[60]; | |
99 | int len; | |
100 | ||
101 | trace_qemu_announce_self_iter(qemu_ether_ntoa(&nic->conf->macaddr)); | |
102 | len = announce_self_create(buf, nic->conf->macaddr.a); | |
103 | ||
104 | qemu_send_packet_raw(qemu_get_queue(nic), buf, len); | |
105 | } | |
106 | static void qemu_announce_self_once(void *opaque) | |
107 | { | |
108 | AnnounceTimer *timer = (AnnounceTimer *)opaque; | |
109 | ||
110 | qemu_foreach_nic(qemu_announce_self_iter, NULL); | |
111 | ||
112 | if (--timer->round) { | |
113 | qemu_announce_timer_step(timer); | |
114 | } else { | |
115 | qemu_announce_timer_del(timer); | |
116 | } | |
117 | } | |
118 | ||
119 | void qemu_announce_self(AnnounceTimer *timer, AnnounceParameters *params) | |
120 | { | |
121 | qemu_announce_timer_reset(timer, params, QEMU_CLOCK_REALTIME, | |
122 | qemu_announce_self_once, timer); | |
123 | if (params->rounds) { | |
124 | qemu_announce_self_once(timer); | |
125 | } else { | |
126 | qemu_announce_timer_del(timer); | |
127 | } | |
128 | } |