Line data Source code
1 : /*
2 : * Copyright (c) 2011-2018 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 : #include <cdp/cdp.h>
16 : #include <vnet/ethernet/packet.h>
17 :
18 : /** \file
19 :
20 : 2 x CDP graph nodes: an "interior" node to process
21 : incoming announcements, and a "process" node to periodically
22 : send announcements.
23 :
24 : The interior node is neither pipelined nor dual-looped, because
25 : it would be very unusual to see more than one CDP packet in
26 : a given input frame. So, it's a very simple / straightforward
27 : example.
28 : */
29 :
30 : /*
31 : * packet counter strings
32 : * Dump these counters via the "show error" CLI command
33 : */
34 : static char *cdp_error_strings[] = {
35 : #define _(sym,string) string,
36 : foreach_cdp_error
37 : #undef _
38 : };
39 :
40 : /*
41 : * We actually send all cdp pkts to the "error" node after scanning
42 : * them, so the graph node has only one next-index. The "error-drop"
43 : * node automatically bumps our per-node packet counters for us.
44 : */
45 : typedef enum
46 : {
47 : CDP_INPUT_NEXT_NORMAL,
48 : CDP_INPUT_N_NEXT,
49 : } cdp_next_t;
50 :
51 : /*
52 : * Process a frame of cdp packets
53 : * Expect 1 packet / frame
54 : */
55 : static uword
56 3 : cdp_node_fn (vlib_main_t * vm,
57 : vlib_node_runtime_t * node, vlib_frame_t * frame)
58 : {
59 : u32 n_left_from, *from;
60 : cdp_input_trace_t *t0;
61 :
62 3 : from = vlib_frame_vector_args (frame); /* array of buffer indices */
63 3 : n_left_from = frame->n_vectors; /* number of buffer indices */
64 :
65 6 : while (n_left_from > 0)
66 : {
67 : u32 bi0;
68 : vlib_buffer_t *b0;
69 : u32 next0, error0;
70 :
71 3 : bi0 = from[0];
72 3 : b0 = vlib_get_buffer (vm, bi0);
73 :
74 3 : next0 = CDP_INPUT_NEXT_NORMAL;
75 :
76 : /* scan this cdp pkt. error0 is the counter index to bump */
77 3 : error0 = cdp_input (vm, b0, bi0);
78 3 : b0->error = node->errors[error0];
79 :
80 : /* If this pkt is traced, snapshoot the data */
81 3 : if (b0->flags & VLIB_BUFFER_IS_TRACED)
82 : {
83 : int len;
84 3 : t0 = vlib_add_trace (vm, node, b0, sizeof (*t0));
85 3 : len = (b0->current_length < sizeof (t0->data))
86 3 : ? b0->current_length : sizeof (t0->data);
87 3 : t0->len = len;
88 3 : clib_memcpy (t0->data, vlib_buffer_get_current (b0), len);
89 : }
90 : /* push this pkt to the next graph node, always error-drop */
91 3 : vlib_set_next_frame_buffer (vm, node, next0, bi0);
92 :
93 3 : from += 1;
94 3 : n_left_from -= 1;
95 : }
96 :
97 3 : return frame->n_vectors;
98 : }
99 :
100 : /*
101 : * cdp input graph node declaration
102 : */
103 : /* *INDENT-OFF* */
104 169388 : VLIB_REGISTER_NODE (cdp_input_node, static) = {
105 : .function = cdp_node_fn,
106 : .name = "cdp-input",
107 : .vector_size = sizeof (u32),
108 : .type = VLIB_NODE_TYPE_INTERNAL,
109 :
110 : .n_errors = CDP_N_ERROR,
111 : .error_strings = cdp_error_strings,
112 :
113 : .format_trace = cdp_input_format_trace,
114 :
115 : .n_next_nodes = CDP_INPUT_N_NEXT,
116 : .next_nodes = {
117 : [CDP_INPUT_NEXT_NORMAL] = "error-drop",
118 : },
119 : };
120 : /* *INDENT-ON* */
121 :
122 : /*
123 : * cdp periodic function
124 : */
125 : static uword
126 1 : cdp_process (vlib_main_t * vm, vlib_node_runtime_t * rt, vlib_frame_t * f)
127 : {
128 1 : cdp_main_t *cm = &cdp_main;
129 : f64 poll_time_remaining;
130 1 : uword event_type, *event_data = 0;
131 :
132 : /* Start w/ cdp disabled */
133 1 : poll_time_remaining = 86400.0;
134 :
135 : while (1)
136 : {
137 : /* sleep until next poll time, or msg serialize event occurs */
138 4 : poll_time_remaining =
139 5 : vlib_process_wait_for_event_or_clock (vm, poll_time_remaining);
140 :
141 4 : event_type = vlib_process_get_events (vm, &event_data);
142 4 : switch (event_type)
143 : {
144 0 : case ~0: /* no events => timeout */
145 0 : break;
146 :
147 4 : case CDP_EVENT_ENABLE:
148 4 : if (!cm->cdp_protocol_registered)
149 : {
150 : /*
151 : * Dynamically register the cdp input node
152 : * with the snap classifier
153 : */
154 1 : snap_register_input_protocol (vm, "cdp-input",
155 : 0xC /* ieee_oui, Cisco */ ,
156 : 0x2000 /* protocol CDP */ ,
157 : cdp_input_node.index);
158 :
159 1 : snap_register_input_protocol (vm, "cdp-input",
160 : 0xC /* ieee_oui, Cisco */ ,
161 : 0x2004 /* protocol CDP */ ,
162 : cdp_input_node.index);
163 : #if 0
164 : /*
165 : * Keep this code for reference...
166 : * Register with the hdlc classifier
167 : */
168 : hdlc_register_input_protocol (vm, HDLC_PROTOCOL_cdp,
169 : cdp_input_node.index);
170 : #endif
171 : /* with ethernet input (for SRP) */
172 1 : ethernet_register_input_type (vm, ETHERNET_TYPE_CDP /* CDP */ ,
173 : cdp_input_node.index);
174 1 : cm->cdp_protocol_registered = 1;
175 : }
176 4 : poll_time_remaining = 10.0;
177 4 : break;
178 :
179 0 : case CDP_EVENT_DISABLE:
180 0 : poll_time_remaining = 86400.0;
181 0 : break;
182 :
183 0 : default:
184 0 : clib_warning ("BUG: event type 0x%wx", event_type);
185 0 : break;
186 : }
187 4 : vec_reset_length (event_data);
188 :
189 : /* peer timeout scan, send announcements */
190 4 : if (vlib_process_suspend_time_is_zero (poll_time_remaining))
191 : {
192 0 : cdp_periodic (vm);
193 0 : poll_time_remaining = 10.0;
194 : }
195 : }
196 :
197 : return 0;
198 : }
199 :
200 : void
201 4 : vnet_cdp_create_periodic_process (cdp_main_t * cmp)
202 : {
203 : /* Already created the process node? */
204 4 : if (cmp->cdp_process_node_index > 0)
205 3 : return;
206 :
207 : /* No, create it now and make a note of the node index */
208 1 : cmp->cdp_process_node_index = vlib_process_create
209 : (cmp->vlib_main, "cdp-process",
210 : cdp_process, 16 /* log2_n_stack_bytes */ );
211 : }
212 :
213 : /*
214 : * fd.io coding-style-patch-verification: ON
215 : *
216 : * Local Variables:
217 : * eval: (c-set-style "gnu")
218 : * End:
219 : */
|