]>
Commit | Line | Data |
---|---|---|
635c5db9 AW |
1 | /* |
2 | * Copyright (c) 2009, 2010, 2011, 2012, 2013 Nicira, Inc. | |
3 | * | |
4 | * Licensed under the Apache License, Version 2.0 (the "License"); | |
5 | * you may not use this file except in compliance with the License. | |
6 | * You may obtain a copy of the License at: | |
7 | * | |
8 | * http://www.apache.org/licenses/LICENSE-2.0 | |
9 | * | |
10 | * Unless required by applicable law or agreed to in writing, software | |
11 | * distributed under the License is distributed on an "AS IS" BASIS, | |
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
13 | * See the License for the specific language governing permissions and | |
14 | * limitations under the License. | |
15 | */ | |
16 | ||
17 | #include <config.h> | |
18 | #include "ofproto-dpif-monitor.h" | |
19 | ||
20 | #include <string.h> | |
21 | ||
22 | #include "bfd.h" | |
23 | #include "cfm.h" | |
24 | #include "hash.h" | |
25 | #include "hmap.h" | |
26 | #include "ofpbuf.h" | |
27 | #include "ofproto-dpif.h" | |
28 | #include "util.h" | |
29 | #include "vlog.h" | |
30 | ||
31 | /* Monitored port. It owns references to ofport, bfd, cfm structs. */ | |
32 | struct mport { | |
33 | struct hmap_node hmap_node; /* In monitor_hmap. */ | |
34 | const struct ofport_dpif *ofport; /* The corresponding ofport. */ | |
35 | ||
36 | struct cfm *cfm; /* Reference to cfm. */ | |
37 | struct bfd *bfd; /* Reference to bfd. */ | |
38 | uint8_t hw_addr[OFP_ETH_ALEN]; /* Hardware address. */ | |
39 | }; | |
40 | ||
41 | /* hmap that contains "struct mport"s. */ | |
42 | static struct hmap monitor_hmap = HMAP_INITIALIZER(&monitor_hmap); | |
43 | ||
44 | static struct ovs_rwlock monitor_rwlock = OVS_RWLOCK_INITIALIZER; | |
45 | ||
46 | static void mport_register(const struct ofport_dpif *, struct bfd *, | |
47 | struct cfm *, uint8_t[ETH_ADDR_LEN]) | |
48 | OVS_REQ_WRLOCK(monitor_rwlock); | |
49 | static void mport_unregister(const struct ofport_dpif *) | |
50 | OVS_REQ_WRLOCK(monitor_rwlock); | |
51 | static void mport_update(struct mport *, struct bfd *, struct cfm *, | |
52 | uint8_t[ETH_ADDR_LEN]) OVS_REQ_WRLOCK(monitor_rwlock); | |
53 | static struct mport *mport_find(const struct ofport_dpif *) | |
54 | OVS_REQ_WRLOCK(monitor_rwlock); | |
55 | ||
56 | /* Tries finding and returning the 'mport' from the monitor_hmap. | |
57 | * If there is no such 'mport', returns NULL. */ | |
58 | static struct mport * | |
59 | mport_find(const struct ofport_dpif *ofport) OVS_REQ_WRLOCK(monitor_rwlock) | |
60 | { | |
61 | struct mport *node; | |
62 | ||
63 | HMAP_FOR_EACH_WITH_HASH (node, hmap_node, hash_pointer(ofport, 0), | |
64 | &monitor_hmap) { | |
65 | if (node->ofport == ofport) { | |
66 | return node; | |
67 | } | |
68 | } | |
69 | return NULL; | |
70 | } | |
71 | ||
72 | /* Creates a new mport and inserts it into monitor_hmap, if it doesn't exist. | |
73 | * Otherwise, just updates its fields. */ | |
74 | static void | |
75 | mport_register(const struct ofport_dpif *ofport, struct bfd *bfd, | |
76 | struct cfm *cfm, uint8_t *hw_addr) | |
77 | OVS_REQ_WRLOCK(monitor_rwlock) | |
78 | { | |
79 | struct mport *mport = mport_find(ofport); | |
80 | ||
81 | if (!mport) { | |
82 | mport = xzalloc(sizeof *mport); | |
83 | mport->ofport = ofport; | |
84 | hmap_insert(&monitor_hmap, &mport->hmap_node, hash_pointer(ofport, 0)); | |
85 | } | |
86 | mport_update(mport, bfd, cfm, hw_addr); | |
87 | } | |
88 | ||
89 | /* Removes mport from monitor_hmap and frees it. */ | |
90 | static void | |
91 | mport_unregister(const struct ofport_dpif *ofport) | |
92 | OVS_REQ_WRLOCK(monitor_rwlock) | |
93 | { | |
94 | struct mport *mport = mport_find(ofport); | |
95 | ||
96 | if (mport) { | |
97 | mport_update(mport, NULL, NULL, NULL); | |
98 | hmap_remove(&monitor_hmap, &mport->hmap_node); | |
99 | free(mport); | |
100 | } | |
101 | } | |
102 | ||
103 | /* Updates the fields of an existing mport struct. */ | |
104 | static void | |
105 | mport_update(struct mport *mport, struct bfd *bfd, struct cfm *cfm, | |
106 | uint8_t hw_addr[ETH_ADDR_LEN]) OVS_REQ_WRLOCK(monitor_rwlock) | |
107 | { | |
108 | ovs_assert(mport); | |
109 | ||
110 | if (mport->cfm != cfm) { | |
111 | cfm_unref(mport->cfm); | |
112 | mport->cfm = cfm_ref(cfm); | |
113 | } | |
114 | if (mport->bfd != bfd) { | |
115 | bfd_unref(mport->bfd); | |
116 | mport->bfd = bfd_ref(bfd); | |
117 | } | |
118 | if (hw_addr && memcmp(mport->hw_addr, hw_addr, ETH_ADDR_LEN)) { | |
119 | memcpy(mport->hw_addr, hw_addr, ETH_ADDR_LEN); | |
120 | } | |
121 | } | |
122 | \f | |
123 | ||
124 | /* Creates the mport in monitor module if either bfd or cfm | |
125 | * is configured. Otherwise, deletes the mport. */ | |
126 | void | |
127 | ofproto_dpif_monitor_port_update(const struct ofport_dpif *ofport, | |
128 | struct bfd *bfd, struct cfm *cfm, | |
129 | uint8_t hw_addr[ETH_ADDR_LEN]) | |
130 | { | |
131 | ovs_rwlock_wrlock(&monitor_rwlock); | |
132 | if (!cfm && !bfd) { | |
133 | mport_unregister(ofport); | |
134 | } else { | |
135 | mport_register(ofport, bfd, cfm, hw_addr); | |
136 | } | |
137 | ovs_rwlock_unlock(&monitor_rwlock); | |
138 | } | |
139 | ||
140 | /* Checks the sending of control packets on all mports. Sends the control | |
141 | * packets if needed. */ | |
142 | void | |
143 | ofproto_dpif_monitor_run_fast(void) | |
144 | { | |
145 | struct mport *mport; | |
146 | static uint32_t buf_stub[128 / 4]; | |
147 | struct ofpbuf packet; | |
148 | ||
149 | ovs_rwlock_rdlock(&monitor_rwlock); | |
150 | HMAP_FOR_EACH (mport, hmap_node, &monitor_hmap) { | |
151 | if (mport->cfm && cfm_should_send_ccm(mport->cfm)) { | |
152 | ofpbuf_use_stub(&packet, buf_stub, sizeof buf_stub); | |
153 | cfm_compose_ccm(mport->cfm, &packet, mport->hw_addr); | |
154 | ofproto_dpif_send_packet(mport->ofport, &packet); | |
155 | } | |
156 | if (mport->bfd && bfd_should_send_packet(mport->bfd)) { | |
157 | ofpbuf_use_stub(&packet, buf_stub, sizeof buf_stub); | |
158 | bfd_put_packet(mport->bfd, &packet, mport->hw_addr); | |
159 | ofproto_dpif_send_packet(mport->ofport, &packet); | |
160 | } | |
161 | } | |
162 | ovs_rwlock_unlock(&monitor_rwlock); | |
163 | } | |
164 | ||
165 | /* Executes bfd_run(), cfm_run() on all mports. */ | |
166 | void | |
167 | ofproto_dpif_monitor_run(void) | |
168 | { | |
169 | struct mport *mport; | |
170 | ||
171 | ovs_rwlock_rdlock(&monitor_rwlock); | |
172 | HMAP_FOR_EACH (mport, hmap_node, &monitor_hmap) { | |
173 | if (mport->cfm) { | |
174 | cfm_run(mport->cfm); | |
175 | } | |
176 | if (mport->bfd) { | |
177 | bfd_run(mport->bfd); | |
178 | } | |
179 | } | |
180 | ovs_rwlock_unlock(&monitor_rwlock); | |
181 | } | |
182 | ||
183 | /* Executes the bfd_wait() and cfm_wait() functions on all mports. */ | |
184 | void | |
185 | ofproto_dpif_monitor_wait(void) | |
186 | { | |
187 | struct mport *mport; | |
188 | ||
189 | ovs_rwlock_rdlock(&monitor_rwlock); | |
190 | HMAP_FOR_EACH (mport, hmap_node, &monitor_hmap) { | |
191 | if (mport->cfm) { | |
192 | cfm_wait(mport->cfm); | |
193 | } | |
194 | if (mport->bfd) { | |
195 | bfd_wait(mport->bfd); | |
196 | } | |
197 | } | |
198 | ovs_rwlock_unlock(&monitor_rwlock); | |
199 | } |