libnet: implemented adding/removing hardware filters from solarflare card
[barrelfish] / lib / net / net_filter.c
1 /*
2  * Copyright (c) 2017, ETH Zurich.
3  * All rights reserved.
4  *
5  * This file is distributed under the terms in the attached LICENSE file.
6  * If you do not find this file, copies can be found by writing to:
7  * ETH Zurich D-INFK, Universitaetsstrasse 6, CH-8092 Zurich. Attn: Systems Group.
8  */
9
10
11 #include <stdio.h>
12 #include <stdlib.h>
13 #include <string.h>
14
15 #include <barrelfish/barrelfish.h>
16 #include <barrelfish/nameservice_client.h>
17 #include <if/net_filter_defs.h>
18 #include <if/net_filter_rpcclient_defs.h>
19
20 #include "include/net/net_filter.h"
21
22 #include "networking_internal.h"
23 #include "debug.h"
24
25 #define MAX_NAME 128
26
27 #define NETDEBUG_SUBSYSTEM "filter"
28
29 struct net_filter_ele {
30     union {
31         struct net_filter_ip ip;
32         struct net_filter_mac mac;
33     } filter;
34     uint64_t filter_id;
35     struct net_filter_ele* next;
36     struct net_filter_ele* prev;
37 };
38
39 struct filter_list {
40     struct net_filter_ele* start;
41     uint64_t num_ele;  
42 };
43
44 struct net_filter_state {
45     struct filter_list filters_ip;
46     struct filter_list filters_mac;
47     struct net_filter_binding* b;
48     volatile bool bound;
49 };
50
51
52 /******************************************************************************
53  * Global state
54  ******************************************************************************/
55
56 static struct net_filter_state filter_state;
57
58 /******************************************************************************
59  * Connection setup
60  ******************************************************************************/
61
62 // Callback for bind
63 static void bind_cb(void *st, errval_t err, struct net_filter_binding *b)
64 {
65     assert(err_is_ok(err));
66
67     NETDEBUG("Sucessfully connected to management interface\n");
68
69     filter_state.b = b;
70     net_filter_rpc_client_init(filter_state.b);
71     filter_state.bound = true;
72 }
73
74
75 /** Open connection to management interface */
76 static errval_t connect_to_net_filter(const char *dev_name)
77 {
78     errval_t r;
79     iref_t iref;
80     const char* prefix = "net_filter_";
81     char name[strlen(dev_name) + strlen(prefix) + 1];
82    
83     // Build label for management service
84     sprintf(name, "%s%s", prefix, dev_name);
85
86     NETDEBUG("Name lookup\n");
87     // Connect to service
88     r = nameservice_blocking_lookup(name, &iref);
89     if (err_is_fail(r)) {
90         return r;
91     }
92
93     NETDEBUG("Binding\n");
94     r = net_filter_bind(iref, bind_cb, &filter_state, get_default_waitset(),
95             IDC_BIND_FLAGS_DEFAULT);
96     if (err_is_fail(r)) {
97         return r;
98     }
99
100     NETDEBUG("Waiting to bind\n");
101     while(filter_state.bound == false) {
102         event_dispatch(get_default_waitset());
103     }
104     
105     NETDEBUG("finished connecting\n");
106     return SYS_ERR_OK;
107 }
108
109 /******************************************************************************
110  * Helper functions
111  ******************************************************************************/
112
113 static bool filter_cmp_ip(struct net_filter_ip* f1, struct net_filter_ip* f2)
114 {
115     if (f1->ip_src == f2->ip_src &&
116         f1->ip_dst == f2->ip_dst &&
117         f1->port_src == f2->port_src &&
118         f1->port_dst == f2->port_dst &&
119         f1->qid == f2->qid &&
120         f1->type == f2->type) {
121         return true;
122     }
123     return false;
124 }
125
126 /*
127 static bool filter_cmp_mac(struct net_filter_mac* f1, struct net_filter_mac* f2)
128 {
129     if (f1->vlan_id == f2->vlan_id &&
130         f1->mac == f2->mac &&
131         f1->type == f2->type) {
132         return true;
133     }
134     return false;
135 }
136 */
137 /*
138 static bool is_reachable(struct net_filter_ip* filt)
139 {
140     struct net_filter_ele* cur = filter_state.filters_ip.start;
141     
142     while(cur != NULL) {
143         printf("reachable: port_dst: %"PRIu16" %"PRIu16" \n", cur->filter.ip.port_dst, filt->port_dst);
144         if (filter_cmp_ip(&cur->filter.ip, filt)) {
145             return true;
146         }
147         cur = cur->next;
148     }
149     return false;
150 }
151 */
152 /******************************************************************************
153  * Library function implementation
154  ******************************************************************************/
155
156 /**
157  * @brief initalized network filtering. Sets up connection to drivers
158  *        which support hardware filtering
159  *
160  * @param cardname  returns the card name to be used
161  *
162  * @return SYS_ERR_OK on success, error on failure
163  */
164 errval_t net_filter_init(const char* cardname)
165 {   
166     errval_t err;
167
168     filter_state.filters_ip.start = NULL;
169     filter_state.filters_ip.num_ele = 0;
170     filter_state.filters_mac.start = NULL;
171     filter_state.filters_mac.num_ele = 0;
172
173     err = connect_to_net_filter(cardname);
174     return err;
175 }
176
177
178 /**
179  * @brief Installs an L3/L4 filter in the hardware filter 
180  *        tables
181  *
182  * @param filt  filter struct
183  *
184  * @return SYS_ERR_OK on success, error on failure
185  */
186 errval_t net_filter_ip_install(struct net_filter_ip* filt)
187 {
188
189     assert(filter_state.bound);
190     errval_t err;
191     uint64_t filter_id;
192
193     struct net_filter_ele* cur = filter_state.filters_ip.start;
194     struct net_filter_ele* prev = NULL;
195
196     /* go through linked list and find last element 
197      (and check if filter is already installed) */
198     if (cur == NULL) {
199         filter_state.filters_ip.start = malloc(sizeof(struct net_filter_ele));
200         cur = filter_state.filters_ip.start;
201     } else {
202         while(cur->next != NULL) {
203             if (filter_cmp_ip(&cur->filter.ip, filt)) {
204                 return NET_FILTER_ERR_ALREADY_EXISTS;
205             }
206             prev = cur;
207             cur = cur->next;
208         }
209
210         if (filter_cmp_ip(&cur->filter.ip, filt)) {
211             return NET_FILTER_ERR_ALREADY_EXISTS;
212         }
213
214         cur->next = malloc(sizeof(struct net_filter_ele));
215         cur = cur->next;
216     }
217
218     cur->filter.ip.ip_src = filt->ip_src;
219     cur->filter.ip.ip_dst = filt->ip_dst;
220     cur->filter.ip.port_src = filt->port_src;
221     cur->filter.ip.port_dst = filt->port_dst;
222     cur->filter.ip.qid = filt->qid;
223     cur->filter.ip.type = filt->type;
224     cur->next = NULL;
225     cur->prev = prev;    
226
227     filter_state.filters_ip.num_ele++;
228
229     err = filter_state.b->rpc_tx_vtbl.install_filter_ip(filter_state.b,
230                                                  filt->type,
231                                                  filt->qid,
232                                                  filt->ip_src,
233                                                  filt->ip_dst,
234                                                  filt->port_src,
235                                                  filt->port_dst,
236                                                  &filter_id);
237     if (err_is_fail(err)) {
238         free(cur);
239         return err;
240     }
241
242     cur->filter_id = filter_id;
243     return SYS_ERR_OK;
244 }
245
246
247 /**
248  * @brief Removes an L3/L4 filter in the hardware filter 
249  *        tables
250  *
251  * @param filt  filter struct
252  *
253  * @return SYS_ERR_OK on success, error on failure
254  */
255 errval_t net_filter_ip_remove(struct net_filter_ip* filt)
256 {
257
258     assert(filter_state.bound);
259     errval_t err, err2;
260     uint64_t filter_id = (uint64_t)-1;
261
262     struct net_filter_ele* cur = filter_state.filters_ip.start;
263     struct net_filter_ele* prev = NULL;
264
265
266     // no entries
267     if (cur == NULL) {
268         return NET_FILTER_ERR_NOT_FOUND;
269     }
270
271     // Multiple entries
272     while(cur != NULL) {
273         if (filter_cmp_ip(&cur->filter.ip, filt)) {
274             filter_id = cur->filter_id;
275             printf("Break \n");
276             break;
277         }
278         prev = cur;
279         cur = cur->next;
280     }
281
282    
283     if (filter_id == (uint64_t) -1) {
284         return NET_FILTER_ERR_NOT_FOUND;
285     }
286
287     err = filter_state.b->rpc_tx_vtbl.remove_filter(filter_state.b,
288                                                     filt->type,
289                                                     filter_id,
290                                                     &err2);
291     if (err_is_fail(err) || err_is_fail(err2)) {
292         return err_is_fail(err) ? err: err2;
293     }
294
295     // remove from queue
296     if (prev != NULL) { // check if first
297         prev->next = cur->next;
298         if (cur->next != NULL) { // check if last
299             cur->next->prev = prev;
300             printf("cur->next->prev id %d \n", cur->next->prev->filter.ip.port_dst);
301             printf("prev->next id %d \n", prev->next->filter.ip.port_dst);
302         } 
303     } else {
304         printf("start id %d \n", filter_state.filters_ip.start->filter.ip.port_dst);
305         filter_state.filters_ip.start = cur->next;
306     }
307     
308
309     free(cur);
310
311     filter_state.filters_ip.num_ele--;
312
313     return SYS_ERR_OK;
314 }
315
316 errval_t net_filter_mac_install(struct net_filter_mac* filt)
317 {
318    USER_PANIC("NYI \n");
319 }
320
321
322 errval_t net_filter_mac_remove(struct net_filter_mac* filt)
323 {
324    USER_PANIC("NYI \n");
325 }
326