libnl  3.2.21
datapath.c
1 /*
2  * lib/openvswitch/datapath.c Open vSwitch datapath
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Lesser General Public
6  * License as published by the Free Software Foundation version 2.1
7  * of the License.
8  *
9  * Copyright (c) 2013 Thomas Graf <tgraf@suug.ch>
10  */
11 
12 /**
13  * @defgroup openvswitch Open vSwitch (libnl-ovs)
14  */
15 
16 /**
17  * @ingroup openvswitch
18  * @defgroup ovs_datapath Open vSwitch Datapath (Fast Path)
19  *
20  * @details
21  * @{
22  */
23 
24 #include <netlink-private/netlink.h>
25 #include <netlink-private/genl.h>
26 #include <netlink/netlink.h>
27 #include <netlink/attr.h>
28 #include <netlink/utils.h>
29 #include <netlink/object.h>
30 #include <netlink/openvswitch/openvswitch.h>
31 #include <netlink/genl/genl.h>
32 #include <netlink/genl/mngt.h>
33 #include <linux/openvswitch.h>
34 
35 /** @cond SKIP */
36 struct ovs_dp {
37  NLHDR_COMMON
38 
39  char dp_name[IFNAMSIZ];
40  int dp_ifindex;
41  uint32_t dp_upcall_pid;
42  uint64_t dp_stats[OVS_DP_STAT_MAX+1];
43 };
44 
45 #define DP_ATTR_NAME (1 << 0)
46 #define DP_ATTR_IFINDEX (1 << 1)
47 #define DP_ATTR_UPCALL_PID (1 << 2)
48 #define DP_ATTR_STATS (1 << 3)
49 
50 static struct nl_cache_ops ovs_dp_cache_ops;
51 static struct nl_object_ops ovs_dp_obj_ops;
52 static struct genl_ops ovs_dp_ops;
53 /** @endcond */
54 
55 static struct nla_policy ovs_dp_policy[OVS_DP_ATTR_MAX+1] = {
56  [OVS_DP_ATTR_NAME] = { .type = NLA_STRING, },
57  [OVS_DP_ATTR_UPCALL_PID]= { .type = NLA_U32 },
58  [OVS_DP_ATTR_STATS] = { .minlen = sizeof(struct ovs_dp_stats) },
59 };
60 
61 static int ovs_dp_msg_parser(struct nl_cache_ops *ops, struct genl_cmd *cmd,
62  struct genl_info *info, void *arg)
63 {
64  struct nl_parser_param *pp = arg;
65  struct ovs_header *hdr = info->userhdr;
66  struct ovs_dp *dp;
67  int err;
68 
69  if (!(dp = ovs_dp_alloc())) {
70  err = -NLE_NOMEM;
71  goto errout;
72  }
73 
74  if (!info->attrs[OVS_DP_ATTR_NAME]) {
75  err = -NLE_MISSING_ATTR;
76  goto errout;
77  }
78 
79  dp->ce_msgtype = info->nlh->nlmsg_type;
80 
81  ovs_dp_set_name(dp, nla_get_string(info->attrs[OVS_DP_ATTR_NAME]));
82  ovs_dp_set_ifindex(dp, hdr->dp_ifindex);
83 
84  if (info->attrs[OVS_DP_ATTR_UPCALL_PID]) {
85  uint32_t upcall = nla_get_u32(info->attrs[OVS_DP_ATTR_UPCALL_PID]);
86  ovs_dp_set_upcall_pid(dp, upcall);
87  }
88 
89  if (info->attrs[OVS_DP_ATTR_STATS]) {
90  struct ovs_dp_stats st;
91 
92  nla_memcpy(&st, info->attrs[OVS_DP_ATTR_STATS], sizeof(st));
93 
94  dp->dp_stats[OVS_DP_STAT_HIT] = st.n_hit;
95  dp->dp_stats[OVS_DP_STAT_MISSED] = st.n_missed;
96  dp->dp_stats[OVS_DP_STAT_LOST] = st.n_lost;
97  dp->dp_stats[OVS_DP_STAT_FLOWS] = st.n_flows;
98  dp->ce_mask |= DP_ATTR_STATS;
99  }
100 
101  err = pp->pp_cb(OBJ_CAST(dp), pp);
102 errout:
103  /* pp->pp_cb() takes care of reference handling */
104  ovs_dp_put(dp);
105 
106  return err;
107 }
108 
109 /** @cond SKIP */
110 struct request_hdr {
111  struct genlmsghdr genl_hdr;
112  struct ovs_header ovs_hdr;
113 };
114 /** @endcond */
115 
116 static int ovs_dp_request_update(struct nl_cache *cache, struct nl_sock *sk)
117 {
118  struct request_hdr hdr = { };
119  int err;
120 
121  if ((err = genl_resolve_id(&ovs_dp_ops)) < 0)
122  return err;
123 
124  hdr.genl_hdr.cmd = OVS_DP_CMD_GET;
125  hdr.genl_hdr.version = OVS_DATAPATH_VERSION;
126 
127  return nl_send_simple(sk, ovs_dp_ops.o_id, NLM_F_DUMP, &hdr, sizeof(hdr));
128 }
129 
130 static void ovs_dp_dump_line(struct nl_object *obj, struct nl_dump_params *p)
131 {
132  struct ovs_dp *dp = (struct ovs_dp *) obj;
133 
134  nl_dump_line(p, "%s ", dp->dp_name);
135 
136  if (dp->ce_mask & DP_ATTR_IFINDEX)
137  nl_dump(p, "ifindex %u ", dp->dp_ifindex);
138 
139  if (dp->ce_mask & DP_ATTR_UPCALL_PID)
140  nl_dump(p, "upcall-pid %u ", dp->dp_upcall_pid);
141 
142  nl_dump(p, "\n");
143 }
144 
145 static void ovs_dp_dump_stats(struct nl_object *obj, struct nl_dump_params *p)
146 {
147  struct ovs_dp *dp = (struct ovs_dp *) obj;
148 
149  ovs_dp_dump_line(obj, p);
150 
151  nl_dump_line(p, " Stats: hit missed lost flows\n");
152  nl_dump_line(p, " %10" PRIu64 " %10" PRIu64 " %10" PRIu64 " %10" PRIu64 "\n",
153  dp->dp_stats[OVS_DP_STAT_HIT],
154  dp->dp_stats[OVS_DP_STAT_MISSED],
155  dp->dp_stats[OVS_DP_STAT_LOST],
156  dp->dp_stats[OVS_DP_STAT_FLOWS]);
157 }
158 
159 static int ovs_dp_compare(struct nl_object *_a, struct nl_object *_b,
160  uint32_t attrs, int flags)
161 {
162  struct ovs_dp *a = (struct ovs_dp *) _a;
163  struct ovs_dp *b = (struct ovs_dp *) _b;
164  int diff = 0;
165 
166 #define DP_DIFF(ATTR, EXPR) ATTR_DIFF(attrs, DP_ATTR_##ATTR, a, b, EXPR)
167 
168  diff |= DP_DIFF(NAME, strcmp(a->dp_name, b->dp_name));
169  diff |= DP_DIFF(IFINDEX, a->dp_ifindex != b->dp_ifindex);
170  diff |= DP_DIFF(UPCALL_PID, a->dp_upcall_pid != b->dp_upcall_pid);
171 
172 #undef DP_DIFF
173 
174  return diff;
175 }
176 
177 /**
178  * @name Retrieving and Lookup
179  * @{
180  */
181 
182 /**
183  * Allocate cache and fill it with all configured datapaths
184  * @arg sk Netlink socket.
185  * @arg result Pointer to store resulting cache.
186  *
187  * Allocates and initializes a new datpath cache. A netlink message is sent
188  * to the kernel requesting a full dump of all configured datpaths. The
189  * returned messages are parsed and filled into the cache.
190  *
191  * @see ovs_dp_lookup()
192  *
193  * @return 0 on success or a negative error code.
194  */
195 int ovs_dp_alloc_cache(struct nl_sock *sk, struct nl_cache **result)
196 {
197  struct nl_cache *cache;
198  int err;
199 
200  if (!(cache = nl_cache_alloc(&ovs_dp_cache_ops)))
201  return -NLE_NOMEM;
202 
203  if (sk && (err = nl_cache_refill(sk, cache)) < 0) {
204  nl_cache_free(cache);
205  return err;
206  }
207 
208  *result = cache;
209  return 0;
210 }
211 
212 /**
213  * Lookup datpath by name
214  * @arg cache Dapath cache
215  * @arg name Name of datapath
216  *
217  * Find a datapath in the cache matching the provided named.
218  *
219  * @attention The reference counter of the returned datpath object will
220  * be incremented. Use ovs_dp_put() to release the reference.
221  *
222  * @see ovs_dp_alloc_cache(0
223  * @see ovs_dp_put()
224  *
225  * @return Datpath object or NULL if no match was found.
226  */
227 struct ovs_dp *ovs_dp_lookup(struct nl_cache *cache, const char *name)
228 {
229  struct ovs_dp *dp;
230 
231  if (cache->c_ops != &ovs_dp_cache_ops)
232  return NULL;
233 
234  nl_list_for_each_entry(dp, &cache->c_items, ce_list) {
235  if (!strcmp(name, dp->dp_name)) {
236  nl_object_get((struct nl_object *) dp);
237  return dp;
238  }
239  }
240 
241  return NULL;
242 }
243 
244 #if 0
245 /**
246  * Get a link object directly from kernel
247  * @arg sk Netlink socket
248  * @arg ifindex Interface index
249  * @arg name Name of link
250  * @arg result Pointer to store resulting link object
251  *
252  * This function builds a \c RTM_GETLINK netlink message to request
253  * a specific link directly from the kernel. The returned answer is
254  * parsed into a struct rtnl_link object and returned via the result
255  * pointer or -NLE_OBJ_NOTFOUND is returned if no matching link was
256  * found.
257  *
258  * @route_doc{link_direct_lookup, Lookup Single Link (Direct Lookup)}
259  * @return 0 on success or a negative error code.
260  */
261 int ovs_dp_get_kernel(struct nl_sock *sk, int ifindex, const char *name,
262  struct rtnl_link **result)
263 {
264  struct nl_msg *msg = NULL;
265  struct nl_object *obj;
266  int err;
267 
268  if ((err = ovs_dp_build_get_request(ifindex, name, &msg)) < 0)
269  return err;
270 
271  err = nl_send_auto(sk, msg);
272  nlmsg_free(msg);
273  if (err < 0)
274  return err;
275 
276  if ((err = nl_pickup(sk, link_msg_parser, &obj)) < 0)
277  return err;
278 
279  /* We have used link_msg_parser(), object is definitely a link */
280  *result = (struct ovs_dp *) obj;
281 
282  /* If an object has been returned, we also need to wait for the ACK */
283  if (err == 0 && obj)
284  wait_for_ack(sk);
285 
286  return 0;
287 }
288 #endif
289 
290 /** @} */
291 
292 static int build_ovs_dp_msg(int cmd, const struct ovs_dp *dp, int flags,
293  struct nl_msg **result)
294 {
295  struct nl_msg *msg;
296  struct ovs_header *hdr;
297  int err;
298 
299  switch (cmd) {
300  case OVS_DP_CMD_NEW:
301  if (!(dp->ce_mask & (DP_ATTR_NAME | DP_ATTR_UPCALL_PID))) {
302  APPBUG("name or upcall-PID must be provided");
303  return -NLE_MISSING_ATTR;
304  }
305  break;
306 
307  case OVS_DP_CMD_DEL:
308  if (!(dp->ce_mask & (DP_ATTR_NAME | DP_ATTR_IFINDEX))) {
309  APPBUG("name or interface index must be provided");
310  return -NLE_MISSING_ATTR;
311  }
312  break;
313  }
314 
315  if ((err = genl_resolve_id(&ovs_dp_ops)) < 0)
316  return err;
317 
318  if (!(msg = nlmsg_alloc()))
319  return -NLE_NOMEM;
320 
321  hdr = genlmsg_put(msg, NL_AUTO_PORT, NL_AUTO_SEQ, ovs_dp_ops.o_id,
322  sizeof(*hdr), flags, cmd, OVS_DATAPATH_VERSION);
323  if (!hdr)
324  goto errout;
325 
326  hdr->dp_ifindex = ovs_dp_get_ifindex(dp);
327 
328  if (dp->ce_mask & DP_ATTR_NAME &&
329  nla_put_string(msg, OVS_DP_ATTR_NAME, dp->dp_name) < 0)
330  goto errout;
331 
332  if (cmd == OVS_DP_CMD_NEW) {
333  if (dp->ce_mask & DP_ATTR_UPCALL_PID &&
334  nla_put_u32(msg, OVS_DP_ATTR_UPCALL_PID, dp->dp_upcall_pid) < 0)
335  goto errout;
336  }
337 
338  *result = msg;
339  return 0;
340 
341 errout:
342  nlmsg_free(msg);
343  return -NLE_MSGSIZE;
344 }
345 
346 /**
347  * @name Addition / Deletion
348  * @{
349  */
350 
351 /**
352  * Build Generic Netlink message requesting addition of OVS datapath
353  * @arg dp Datapath object
354  * @arg flags Additional netlink message flags (unused)
355  * @arg result Pointer to store resulting Netlink message
356  *
357  * Identical to ovs_dp_add() but returns message instead of sending
358  * it to the kernel.
359  *
360  * @see ovs_dp_add()
361  *
362  * @return 0 on success or a negative error code.
363  */
364 int ovs_dp_build_add_request(const struct ovs_dp *dp, int flags,
365  struct nl_msg **result)
366 {
367  return build_ovs_dp_msg(OVS_DP_CMD_NEW, dp, flags, result);
368 }
369 
370 /**
371  * Add OVS datapath
372  * @arg sk Netlink socket.
373  * @arg dp Datapath object
374  * @arg flags Additional netlink message flags (unused)
375  *
376  * Builds a Generic Netlink message with command \c OVS_DP_CMD_NEW requesting
377  * the addition of a new Open vSwitch datapath and sends the message to the
378  * kernel.
379  *
380  * After sending, the function will wait for the ACK or an eventual error
381  * message and thus blocks until the operation has been completed.
382  *
383  * @see ovs_dp_build_add_request()
384  *
385  * @copydoc auto_ack_warning
386  *
387  * @return 0 on success or a negative error code.
388  */
389 int ovs_dp_add(struct nl_sock *sk, const struct ovs_dp *dp, int flags)
390 {
391  struct nl_msg *msg;
392  int err;
393 
394  err = ovs_dp_build_add_request(dp, flags, &msg);
395  if (err < 0)
396  return err;
397 
398  return nl_send_sync(sk, msg);
399 }
400 
401 /**
402  * Build Generic Netlink message requesting deletion of OVS datapath
403  * @arg dp Datapath object to delete
404  * @arg flags Additional netlink message flags (unused)
405  * @arg result Pointer to store resulting Netlink message
406  *
407  * Identical to ovs_dp_delete() but returns message instead of sending
408  * it to the kernel.
409  *
410  * @see ovs_dp_delete()
411  *
412  * @return 0 on success or a negative error code.
413  */
414 int ovs_dp_build_delete_request(const struct ovs_dp *dp, int flags,
415  struct nl_msg **result)
416 {
417  return build_ovs_dp_msg(OVS_DP_CMD_DEL, dp, flags, result);
418 }
419 
420 /**
421  * Delete OVS datapath
422  * @arg sk Netlink socket.
423  * @arg dp Datapath object
424  * @arg flags Additional netlink message flags (unused)
425  *
426  * Builds a Generic Netlink message with command \c OVS_DP_CMD_DEL requesting
427  * the deletion of a new Open vSwitch datapath and sends the message to the
428  * kernel.
429  *
430  * After sending, the function will wait for the ACK or an eventual error
431  * message and thus blocks until the operation has been completed.
432  *
433  * @see ovs_dp_build_add_request()
434  *
435  * @copydoc auto_ack_warning
436  *
437  * @return 0 on success or a negative error code.
438  */
439 int ovs_dp_delete(struct nl_sock *sk, const struct ovs_dp *dp, int flags)
440 {
441  struct nl_msg *msg;
442  int err;
443 
444  if ((err = ovs_dp_build_delete_request(dp, 0, &msg)) < 0)
445  return err;
446 
447  return nl_send_sync(sk, msg);
448 }
449 
450 /** @} */
451 
452 /**
453  * @name Accessing Datapath Attributes
454  * @{
455  */
456 
457 /**
458  * Allocate Open vSwitch Datapath
459  *
460  * @see ovs_dp_put()
461  * @return New datapath object or NULL if allocation failed
462  */
463 struct ovs_dp *ovs_dp_alloc(void)
464 {
465  return (struct ovs_dp *) nl_object_alloc(&ovs_dp_obj_ops);
466 }
467 
468 /**
469  * Give up reference to a datpath object
470  * @arg dp Datapath object
471  */
472 void ovs_dp_put(struct ovs_dp *dp)
473 {
474  nl_object_put(OBJ_CAST(dp));
475 }
476 
477 /**
478  * Set datpath name
479  * @arg dp Datapath object
480  * @arg name New name
481  *
482  * @copydoc read_only_attribute
483  * @see ovs_dp_get_name()
484  */
485 void ovs_dp_set_name(struct ovs_dp *dp, const char *name)
486 {
487  strncpy(dp->dp_name, name, sizeof(dp->dp_name) - 1);
488  dp->ce_mask |= DP_ATTR_NAME;
489 }
490 
491 /**
492  * Return datpath name
493  * @arg dp Datapath object
494  *
495  * @see ovs_dp_set_name()
496  * @return Datapath name or NULL if name is not specified
497  */
498 const char *ovs_dp_get_name(const struct ovs_dp *dp)
499 {
500  return dp->ce_mask & DP_ATTR_NAME ? dp->dp_name : NULL;
501 }
502 
503 /**
504  * Set interface index of datapath port
505  * @arg dp Datapath object
506  * @arg ifindex Interface index
507  *
508  * @see ovs_dp_get_ifindex()
509  */
510 void ovs_dp_set_ifindex(struct ovs_dp *dp, int ifindex)
511 {
512  dp->dp_ifindex = ifindex;
513  dp->ce_mask |= DP_ATTR_IFINDEX;
514 }
515 
516 /**
517  * Return interface index of datapath port
518  * @arg dp Datapath object
519  *
520  * @see ovs_dp_set_ifindex()
521  *
522  * @return Interface index or 0 if not set.
523  */
524 int ovs_dp_get_ifindex(const struct ovs_dp *dp)
525 {
526  return dp->dp_ifindex;
527 }
528 
529 /**
530  * Set upcall PID
531  * @arg dp Datapath object
532  * @arg pid Upcall PID
533  *
534  * @see ovs_dp_get_upcall_pid()
535  */
536 void ovs_dp_set_upcall_pid(struct ovs_dp *dp, int pid)
537 {
538  dp->dp_upcall_pid = pid;
539  dp->ce_mask |= DP_ATTR_UPCALL_PID;
540 }
541 
542 /**
543  * Return upcall PID
544  * @arg dp Datapath object
545  *
546  * @see ovs_dp_set_upcall_pid()
547  *
548  * @return Upcall PID or 0 if not set.
549  */
550 int ovs_dp_get_upcall_pid(const struct ovs_dp *dp)
551 {
552  return dp->dp_upcall_pid;
553 }
554 
555 /** @} */
556 
557 /**
558  * @name Statistics
559  * @{
560  */
561 
562 /**
563  * Return value of datapath statistics counter
564  * @arg dp Datapath object
565  * @arg id Identifier of statistical counter
566  *
567  * @return Value of counter or 0 if not specified.
568  */
569 uint64_t ovs_dp_get_stat(const struct ovs_dp *dp, ovs_dp_stat_id_t id)
570 {
571  if (id > OVS_DP_STAT_MAX)
572  return 0;
573 
574  return dp->dp_stats[id];
575 }
576 
577 /**
578  * Set value of datpath statistics counter
579  * @arg dp Datpath object
580  * @arg id Identifier of statistical counter
581  * @arg value New value
582  *
583  * \note Changing the value of a statistical counter will not change the
584  * value in the kernel.
585  *
586  * @return 0 on success or a negative error code
587  */
589  const uint64_t value)
590 {
591  if (id > OVS_DP_STAT_MAX)
592  return -NLE_INVAL;
593 
594  dp->dp_stats[id] = value;
595 
596  return 0;
597 }
598 
599 
600 static const struct trans_tbl dp_stats[] = {
601  __ADD(OVS_DP_STAT_HIT, hit)
602  __ADD(OVS_DP_STAT_MISSED, missed)
603  __ADD(OVS_DP_STAT_LOST, lost)
604  __ADD(OVS_DP_STAT_FLOWS, flows)
605 };
606 
607 /**
608  * Translate datapath statistic ID to name
609  * @arg st Datapath statistic identifier
610  * @arg buf Buffer to store name
611  * @arg len Length of buffer
612  *
613  * @return Pointer to buffer
614  */
615 const char *ovs_dp_stat2str(ovs_dp_stat_id_t st, char *buf, size_t len)
616 {
617  return __type2str(st, buf, len, dp_stats, ARRAY_SIZE(dp_stats));
618 }
619 
620 /**
621  * Translate datapath statistic name to identifier
622  * @arg name Name of datapath statistic identifier
623  *
624  * @return Numeric identifier if found or NULL
625  */
626 int ovs_dp_str2stat(const char *name)
627 {
628  return __str2type(name, dp_stats, ARRAY_SIZE(dp_stats));
629 }
630 
631 /** @} */
632 
633 static struct nl_object_ops ovs_dp_obj_ops = {
634  .oo_name = "openvswitch/datapath",
635  .oo_size = sizeof(struct ovs_dp),
636  .oo_dump = {
637  [NL_DUMP_LINE] = ovs_dp_dump_line,
638  [NL_DUMP_STATS] = ovs_dp_dump_stats,
639  },
640  .oo_compare = ovs_dp_compare,
641  .oo_id_attrs = DP_ATTR_NAME,
642 };
643 
644 static struct genl_cmd ovs_dp_cmds[] = {
645  {
646  .c_id = OVS_DP_CMD_NEW,
647  .c_name = "NEW_DATAPATH" ,
648  .c_maxattr = OVS_DP_ATTR_MAX,
649  .c_attr_policy = ovs_dp_policy,
650  .c_msg_parser = ovs_dp_msg_parser,
651  },
652  {
653  .c_id = OVS_DP_CMD_DEL,
654  .c_name = "DEL_DATAPATH" ,
655  },
656  {
657  .c_id = OVS_DP_CMD_GET,
658  .c_name = "GET_DATAPATH" ,
659  .c_maxattr = OVS_DP_ATTR_MAX,
660  .c_attr_policy = ovs_dp_policy,
661  .c_msg_parser = ovs_dp_msg_parser,
662  },
663  {
664  .c_id = OVS_DP_CMD_SET,
665  .c_name = "SET_DATAPATH" ,
666  },
667 };
668 
669 static struct genl_ops ovs_dp_ops = {
670  .o_cmds = ovs_dp_cmds,
671  .o_ncmds = ARRAY_SIZE(ovs_dp_cmds),
672 };
673 
674 static struct nl_cache_ops ovs_dp_cache_ops = {
675  .co_name = "openvswitch/datapath",
676  .co_hdrsize = GENL_HDRSIZE(sizeof(struct ovs_header)),
677  .co_msgtypes = GENL_FAMILY(GENL_ID_GENERATE, "ovs_datapath"),
678  .co_genl = &ovs_dp_ops,
679  .co_protocol = NETLINK_GENERIC,
680  .co_request_update = ovs_dp_request_update,
681  .co_obj_ops = &ovs_dp_obj_ops,
682 };
683 
684 static void __init ovs_datapath_init(void)
685 {
686  if (genl_register(&ovs_dp_cache_ops) < 0)
687  BUG();
688 }
689 
690 static void __exit ovs_datapath_exit(void)
691 {
692  genl_unregister(&ovs_dp_cache_ops);
693 }
694 
695 /** @} */