Line data Source code
1 : /*
2 : * Copyright (c) 2016 Cisco and/or its affiliates.
3 : * Licensed under the Apache License, Version 2.0 (the "License");
4 : * you may not use this file except in compliance with the License.
5 : * You may obtain a copy of the License at:
6 : *
7 : * http://www.apache.org/licenses/LICENSE-2.0
8 : *
9 : * Unless required by applicable law or agreed to in writing, software
10 : * distributed under the License is distributed on an "AS IS" BASIS,
11 : * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 : * See the License for the specific language governing permissions and
13 : * limitations under the License.
14 : */
15 :
16 :
17 : #include <vnet/vnet.h>
18 : #include <vnet/mfib/mfib_signal.h>
19 : #include <vppinfra/dlist.h>
20 :
21 : /**
22 : * @brief Pool of signals
23 : */
24 : static mfib_signal_t *mfib_signal_pool;
25 :
26 : /**
27 : * @brief pool of dlist elements
28 : */
29 : static dlist_elt_t *mfib_signal_dlist_pool;
30 :
31 : /**
32 : * the list/set of interfaces with signals pending
33 : */
34 : typedef struct mfib_signal_q_t_
35 : {
36 : /**
37 : * the dlist indext that is the head of the list
38 : */
39 : u32 mip_head;
40 :
41 : /**
42 : * Spin lock to protect the list
43 : */
44 : int mip_lock;
45 : } mfib_signal_q_t;
46 :
47 : /**
48 : * @brief The pending queue of signals to deliver to the control plane
49 : */
50 : static mfib_signal_q_t mfib_signal_pending ;
51 :
52 : static void
53 575 : mfib_signal_list_init (void)
54 : {
55 : dlist_elt_t *head;
56 : u32 hi;
57 :
58 575 : pool_get(mfib_signal_dlist_pool, head);
59 575 : hi = head - mfib_signal_dlist_pool;
60 :
61 575 : mfib_signal_pending.mip_head = hi;
62 575 : clib_dlist_init(mfib_signal_dlist_pool, hi);
63 575 : }
64 :
65 : void
66 575 : mfib_signal_module_init (void)
67 : {
68 575 : mfib_signal_list_init();
69 575 : }
70 :
71 : static inline void
72 37 : mfib_signal_lock_aquire (void)
73 : {
74 37 : while (clib_atomic_test_and_set (&mfib_signal_pending.mip_lock))
75 : ;
76 37 : }
77 :
78 : static inline void
79 37 : mfib_signal_lock_release (void)
80 : {
81 37 : clib_atomic_release(&mfib_signal_pending.mip_lock);
82 37 : }
83 :
84 : #define MFIB_SIGNAL_CRITICAL_SECTION(_body) \
85 : { \
86 : mfib_signal_lock_aquire(); \
87 : do { \
88 : _body; \
89 : } while (0); \
90 : mfib_signal_lock_release(); \
91 : }
92 :
93 : int
94 15 : mfib_signal_send_one (struct vl_api_registration_ *reg,
95 : u32 context)
96 : {
97 : u32 li, si;
98 :
99 : /*
100 : * with the lock held, pop a signal from the q.
101 : */
102 15 : MFIB_SIGNAL_CRITICAL_SECTION(
103 : ({
104 : li = clib_dlist_remove_head(mfib_signal_dlist_pool,
105 : mfib_signal_pending.mip_head);
106 : }));
107 :
108 15 : if (~0 != li)
109 : {
110 : mfib_signal_t *mfs;
111 : mfib_itf_t *mfi;
112 : dlist_elt_t *elt;
113 :
114 7 : elt = pool_elt_at_index(mfib_signal_dlist_pool, li);
115 7 : si = elt->value;
116 :
117 7 : mfs = pool_elt_at_index(mfib_signal_pool, si);
118 7 : mfi = mfib_itf_get(mfs->mfs_itf);
119 7 : mfi->mfi_si = INDEX_INVALID;
120 7 : clib_atomic_fetch_and(&mfi->mfi_flags,
121 : ~MFIB_ITF_FLAG_SIGNAL_PRESENT);
122 :
123 :
124 7 : vl_mfib_signal_send_one(reg, context, mfs);
125 :
126 : /*
127 : * with the lock held, return the resoruces of the signals posted
128 : */
129 7 : MFIB_SIGNAL_CRITICAL_SECTION(
130 : ({
131 : pool_put_index(mfib_signal_pool, si);
132 : pool_put_index(mfib_signal_dlist_pool, li);
133 : }));
134 :
135 7 : return (1);
136 : }
137 8 : return (0);
138 : }
139 :
140 : void
141 11 : mfib_signal_push (const mfib_entry_t *mfe,
142 : mfib_itf_t *mfi,
143 : vlib_buffer_t *b0)
144 : {
145 : mfib_signal_t *mfs;
146 : dlist_elt_t *elt;
147 : u32 si, li;
148 :
149 11 : MFIB_SIGNAL_CRITICAL_SECTION(
150 : ({
151 : pool_get(mfib_signal_pool, mfs);
152 : pool_get(mfib_signal_dlist_pool, elt);
153 :
154 : si = mfs - mfib_signal_pool;
155 : li = elt - mfib_signal_dlist_pool;
156 :
157 : elt->value = si;
158 : mfi->mfi_si = li;
159 :
160 : clib_dlist_addhead(mfib_signal_dlist_pool,
161 : mfib_signal_pending.mip_head,
162 : li);
163 : }));
164 :
165 11 : mfs->mfs_entry = mfib_entry_get_index(mfe);
166 11 : mfs->mfs_itf = mfib_itf_get_index(mfi);
167 :
168 11 : if (NULL != b0)
169 : {
170 7 : mfs->mfs_buffer_len = b0->current_length;
171 7 : memcpy(mfs->mfs_buffer,
172 7 : vlib_buffer_get_current(b0),
173 : (mfs->mfs_buffer_len > MFIB_SIGNAL_BUFFER_SIZE ?
174 : MFIB_SIGNAL_BUFFER_SIZE :
175 7 : mfs->mfs_buffer_len));
176 : }
177 : else
178 : {
179 4 : mfs->mfs_buffer_len = 0;
180 : }
181 11 : }
182 :
183 : void
184 16192 : mfib_signal_remove_itf (const mfib_itf_t *mfi)
185 : {
186 : u32 li;
187 :
188 : /*
189 : * lock the queue to prevent further additions while we fiddle.
190 : */
191 16192 : li = mfi->mfi_si;
192 :
193 16192 : if (INDEX_INVALID != li)
194 : {
195 : /*
196 : * it's in the pending q
197 : */
198 4 : MFIB_SIGNAL_CRITICAL_SECTION(
199 : ({
200 : dlist_elt_t *elt;
201 :
202 : /*
203 : * with the lock held;
204 : * - remove the signal from the pending list
205 : * - free up the signal and list entry obejcts
206 : */
207 : clib_dlist_remove(mfib_signal_dlist_pool, li);
208 :
209 : elt = pool_elt_at_index(mfib_signal_dlist_pool, li);
210 : pool_put_index(mfib_signal_pool, elt->value);
211 : pool_put(mfib_signal_dlist_pool, elt);
212 : }));
213 : }
214 16192 : }
|