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