lxcpp: fix cgroup unit tests
[platform/core/security/vasum.git] / server / netdev.cpp
1 /*
2  *  Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved
3  *
4  *  Contact: Mateusz Malicki <m.malicki2@samsung.com>
5  *
6  *  Licensed under the Apache License, Version 2.0 (the "License");
7  *  you may not use this file except in compliance with the License.
8  *  You may obtain a copy of the License at
9  *
10  *      http://www.apache.org/licenses/LICENSE-2.0
11  *
12  *  Unless required by applicable law or agreed to in writing, software
13  *  distributed under the License is distributed on an "AS IS" BASIS,
14  *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15  *  See the License for the specific language governing permissions and
16  *  limitations under the License
17  */
18
19 /**
20  * @file
21  * @author  Mateusz Malicki (m.malicki2@samsung.com)
22  * @brief   Network devices management functions definition
23  */
24
25 #include "config.hpp"
26 #include "netdev.hpp"
27 #include "netlink/netlink-message.hpp"
28 #include "utils/make-clean.hpp"
29 #include "utils/exception.hpp"
30 #include "utils.hpp"
31 #include "exception.hpp"
32 #include "logger/logger.hpp"
33
34 #include <algorithm>
35 #include <string>
36 #include <cstdint>
37 #include <cstring>
38 #include <cassert>
39 #include <sstream>
40 #include <set>
41
42 #include <boost/algorithm/string/split.hpp>
43 #include <boost/algorithm/string/classification.hpp>
44
45 #include <net/if.h>
46 #include <unistd.h>
47 #include <sys/ioctl.h>
48 #include <arpa/inet.h>
49 #include <ifaddrs.h>
50 #include <linux/rtnetlink.h>
51 #include <linux/veth.h>
52 #include <linux/sockios.h>
53 #include <linux/if_link.h>
54 #include <linux/rtnetlink.h>
55 #include <linux/if_bridge.h>
56
57 //IFLA_BRIDGE_FLAGS and BRIDGE_FLAGS_MASTER
58 //should be defined in linux/if_bridge.h since kernel v3.7
59 #ifndef IFLA_BRIDGE_FLAGS
60 #define IFLA_BRIDGE_FLAGS 0
61 #endif
62 #ifndef BRIDGE_FLAGS_MASTER
63 #define BRIDGE_FLAGS_MASTER 1
64 #endif
65
66 using namespace utils;
67 using namespace vasum::netlink;
68 using std::get;
69
70 namespace vasum {
71 namespace netdev {
72
73 namespace {
74
75 std::string getUniqueVethName()
76 {
77     auto find = [](const ifaddrs* ifaddr, const std::string& name) -> bool {
78         for (const ifaddrs* ifa = ifaddr; ifa != NULL; ifa = ifa->ifa_next) {
79             if (name == ifa->ifa_name) {
80                 return true;
81             }
82         }
83         return false;
84     };
85
86     ifaddrs* ifaddr;
87     getifaddrs(&ifaddr);
88     std::string newName;
89     int i = 0;
90     do {
91         newName = "veth0" + std::to_string(++i);
92     } while (find(ifaddr, newName));
93
94     freeifaddrs(ifaddr);
95     return newName;
96 }
97
98 uint32_t getInterfaceIndex(const std::string& name) {
99     uint32_t index = if_nametoindex(name.c_str());
100     if (!index) {
101         const std::string msg = "Can't get " + name + " interface index (" + getSystemErrorMessage() + ")";
102         LOGE(msg);
103         throw ZoneOperationException(msg);
104     }
105     return index;
106 }
107
108 uint32_t getInterfaceIndex(const std::string& name, pid_t nsPid) {
109     NetlinkMessage nlm(RTM_GETLINK, NLM_F_REQUEST | NLM_F_ACK);
110     ifinfomsg infoPeer = utils::make_clean<ifinfomsg>();
111     infoPeer.ifi_family = AF_UNSPEC;
112     infoPeer.ifi_change = 0xFFFFFFFF;
113     nlm.put(infoPeer)
114         .put(IFLA_IFNAME, name);
115     NetlinkResponse response = send(nlm, nsPid);
116     if (!response.hasMessage()) {
117         throw VasumException("Can't get interface index");
118     }
119
120     response.fetch(infoPeer);
121     return infoPeer.ifi_index;
122 }
123
124 int getIpFamily(const std::string& ip)
125 {
126     return ip.find(':') == std::string::npos ? AF_INET : AF_INET6;
127 }
128
129 void validateNetdevName(const std::string& name)
130 {
131     if (name.size() <= 1 || name.size() >= IFNAMSIZ) {
132         throw ZoneOperationException("Invalid netdev name format");
133     }
134 }
135
136 void createPipedNetdev(const std::string& netdev1, const std::string& netdev2)
137 {
138     validateNetdevName(netdev1);
139     validateNetdevName(netdev2);
140
141     NetlinkMessage nlm(RTM_NEWLINK, NLM_F_REQUEST | NLM_F_CREATE | NLM_F_EXCL | NLM_F_ACK);
142     ifinfomsg infoPeer = utils::make_clean<ifinfomsg>();
143     infoPeer.ifi_family = AF_UNSPEC;
144     infoPeer.ifi_change = 0xFFFFFFFF;
145     nlm.put(infoPeer)
146         .beginNested(IFLA_LINKINFO)
147             .put(IFLA_INFO_KIND, "veth")
148             .beginNested(IFLA_INFO_DATA)
149                 .beginNested(VETH_INFO_PEER)
150                     .put(infoPeer)
151                     .put(IFLA_IFNAME, netdev2)
152                 .endNested()
153             .endNested()
154         .endNested()
155         .put(IFLA_IFNAME, netdev1);
156     send(nlm);
157 }
158
159 void attachToBridge(const std::string& bridge, const std::string& netdev)
160 {
161     validateNetdevName(bridge);
162     validateNetdevName(netdev);
163
164     uint32_t index = getInterfaceIndex(netdev);
165     int fd = socket(AF_LOCAL, SOCK_STREAM, 0);
166     if (fd < 0) {
167         const std::string msg = "Can't open socket (" + getSystemErrorMessage() + ")";
168         LOGE(msg);
169         throw ZoneOperationException(msg);
170     }
171
172     struct ifreq ifr = utils::make_clean<ifreq>();
173     strncpy(ifr.ifr_name, bridge.c_str(), IFNAMSIZ);
174     ifr.ifr_ifindex = index;
175     int err = ioctl(fd, SIOCBRADDIF, &ifr);
176     if (err < 0) {
177         int error = errno;
178         //TODO: Close can be interrupted. Move util functions from ipc
179         ::close(fd);
180         const std::string msg = "Can't attach to bridge (" + getSystemErrorMessage(error) + ")";
181         LOGE(msg);
182         throw ZoneOperationException(msg);
183     }
184     close(fd);
185 }
186
187 int setFlags(const std::string& name, uint32_t mask, uint32_t flags)
188 {
189     uint32_t index = getInterfaceIndex(name);
190     NetlinkMessage nlm(RTM_NEWLINK, NLM_F_REQUEST | NLM_F_ACK);
191     ifinfomsg infoPeer = utils::make_clean<ifinfomsg>();
192     infoPeer.ifi_family = AF_UNSPEC;
193     infoPeer.ifi_index = index;
194     infoPeer.ifi_flags = flags;
195     // since kernel v2.6.22 ifi_change is used to change only selected flags;
196     infoPeer.ifi_change = mask;
197     nlm.put(infoPeer);
198     send(nlm);
199     return 0;
200 }
201
202 void up(const std::string& netdev)
203 {
204     setFlags(netdev, IFF_UP, IFF_UP);
205 }
206
207 void moveToNS(const std::string& netdev, pid_t pid)
208 {
209     uint32_t index = getInterfaceIndex(netdev);
210     NetlinkMessage nlm(RTM_NEWLINK, NLM_F_REQUEST | NLM_F_ACK);
211     ifinfomsg infopeer = utils::make_clean<ifinfomsg>();
212     infopeer.ifi_family = AF_UNSPEC;
213     infopeer.ifi_index = index;
214     nlm.put(infopeer)
215         .put(IFLA_NET_NS_PID, pid);
216     send(nlm);
217 }
218
219 void createMacvlan(const std::string& master, const std::string& slave, const macvlan_mode& mode)
220 {
221     validateNetdevName(master);
222     validateNetdevName(slave);
223
224     uint32_t index = getInterfaceIndex(master);
225     NetlinkMessage nlm(RTM_NEWLINK, NLM_F_REQUEST|NLM_F_CREATE|NLM_F_EXCL|NLM_F_ACK);
226     ifinfomsg infopeer = utils::make_clean<ifinfomsg>();
227     infopeer.ifi_family = AF_UNSPEC;
228     infopeer.ifi_change = 0xFFFFFFFF;
229     nlm.put(infopeer)
230         .beginNested(IFLA_LINKINFO)
231             .put(IFLA_INFO_KIND, "macvlan")
232             .beginNested(IFLA_INFO_DATA)
233                 .put(IFLA_MACVLAN_MODE, static_cast<uint32_t>(mode))
234             .endNested()
235         .endNested()
236         .put(IFLA_LINK, index)
237         .put(IFLA_IFNAME, slave);
238     send(nlm);
239 }
240
241 std::vector<Attrs> getIpAddresses(const pid_t nsPid, int family, uint32_t index)
242 {
243     NetlinkMessage nlm(RTM_GETADDR, NLM_F_REQUEST | NLM_F_ACK | NLM_F_DUMP);
244     ifaddrmsg infoAddr = utils::make_clean<ifaddrmsg>();
245     infoAddr.ifa_family = family;
246     nlm.put(infoAddr);
247     NetlinkResponse response = send(nlm, nsPid);
248     if (!response.hasMessage()) {
249         //There is no interfaces with addresses
250         return std::vector<Attrs>();
251     }
252
253     std::vector<Attrs> addresses;
254     while (response.hasMessage()) {
255         ifaddrmsg addrmsg;
256         response.fetch(addrmsg);
257         if (addrmsg.ifa_index == index) {
258             Attrs attrs;
259             attrs.push_back(make_tuple("prefixlen", std::to_string(addrmsg.ifa_prefixlen)));
260             attrs.push_back(make_tuple("flags", std::to_string(addrmsg.ifa_flags)));
261             attrs.push_back(make_tuple("scope", std::to_string(addrmsg.ifa_scope)));
262             attrs.push_back(make_tuple("family", std::to_string(addrmsg.ifa_family)));
263             while (response.hasAttribute()) {
264                 assert(INET6_ADDRSTRLEN >= INET_ADDRSTRLEN);
265                 char buf[INET6_ADDRSTRLEN];
266                 in6_addr addr6;
267                 in_addr addr4;
268                 const void* addr = NULL;
269                 int attrType = response.getAttributeType();
270                 switch (attrType) {
271                     case IFA_ADDRESS:
272                         if (family == AF_INET6) {
273                             response.fetch(IFA_ADDRESS, addr6);
274                             addr = &addr6;
275                         } else {
276                             assert(family == AF_INET);
277                             response.fetch(IFA_ADDRESS, addr4);
278                             addr = &addr4;
279                         }
280                         addr = inet_ntop(family, addr, buf, sizeof(buf));
281                         if (addr == NULL) {
282                             const std::string msg = "Can't convert ip address: " + getSystemErrorMessage();
283                             LOGE(msg);
284                             throw VasumException(msg);
285                         }
286                         attrs.push_back(std::make_tuple("ip", buf));
287                         break;
288                     default:
289                         response.skipAttribute();
290                         break;
291                 }
292             }
293             addresses.push_back(std::move(attrs));
294         }
295         response.fetchNextMessage();
296     }
297     return addresses;
298 }
299
300 void  setIpAddresses(const pid_t nsPid,
301                      const uint32_t index,
302                      const Attrs& attrs,
303                      int family)
304 {
305     NetlinkMessage nlm(RTM_NEWADDR, NLM_F_CREATE | NLM_F_REQUEST | NLM_F_ACK);
306     ifaddrmsg infoAddr = utils::make_clean<ifaddrmsg>();
307     infoAddr.ifa_family = family;
308     infoAddr.ifa_index = index;
309     for (const auto& attr : attrs) {
310         if (get<0>(attr) == "prefixlen") {
311             infoAddr.ifa_prefixlen = stoul(get<1>(attr));
312         }
313         if (get<0>(attr) == "flags") {
314             infoAddr.ifa_flags = stoul(get<1>(attr));
315         }
316         if (get<0>(attr) == "scope") {
317             infoAddr.ifa_scope = stoul(get<1>(attr));
318         }
319     }
320     nlm.put(infoAddr);
321     for (const auto& attr : attrs) {
322         if (get<0>(attr) == "ip") {
323             if (family == AF_INET6) {
324                 in6_addr addr6;
325                 if (inet_pton(AF_INET6, get<1>(attr).c_str(), &addr6) != 1) {
326                     throw VasumException("Can't set ipv4 address");
327                 };
328                 nlm.put(IFA_ADDRESS, addr6);
329                 nlm.put(IFA_LOCAL, addr6);
330             } else {
331                 assert(family == AF_INET);
332                 in_addr addr4;
333                 if (inet_pton(AF_INET, get<1>(attr).c_str(), &addr4) != 1) {
334                     throw VasumException("Can't set ipv6 address");
335                 };
336                 nlm.put(IFA_LOCAL, addr4);
337             }
338         }
339     }
340     send(nlm, nsPid);
341 }
342
343 void deleteIpAddress(const pid_t nsPid,
344                      const uint32_t index,
345                      const std::string& ip,
346                      int prefixlen,
347                      int family)
348 {
349     NetlinkMessage nlm(RTM_DELADDR, NLM_F_REQUEST | NLM_F_ACK);
350     ifaddrmsg infoAddr = utils::make_clean<ifaddrmsg>();
351     infoAddr.ifa_family = family;
352     infoAddr.ifa_index = index;
353     infoAddr.ifa_prefixlen = prefixlen;
354     nlm.put(infoAddr);
355     if (family == AF_INET6) {
356         in6_addr addr6;
357         if (inet_pton(AF_INET6, ip.c_str(), &addr6) != 1) {
358             throw VasumException("Can't delete ipv6 address");
359         };
360         nlm.put(IFA_ADDRESS, addr6);
361         nlm.put(IFA_LOCAL, addr6);
362     } else {
363         assert(family == AF_INET);
364         in_addr addr4;
365         if (inet_pton(AF_INET, ip.c_str(), &addr4) != 1) {
366             throw VasumException("Can't delete ipv4 address");
367         };
368         nlm.put(IFA_LOCAL, addr4);
369     }
370     send(nlm, nsPid);
371 }
372
373 } // namespace
374
375 void createVeth(const pid_t& nsPid, const std::string& nsDev, const std::string& hostDev)
376 {
377     std::string hostVeth = getUniqueVethName();
378     LOGT("Creating veth: bridge: " << hostDev << ", port: " << hostVeth << ", zone: " << nsDev);
379     createPipedNetdev(nsDev, hostVeth);
380     try {
381         attachToBridge(hostDev, hostVeth);
382         up(hostVeth);
383         moveToNS(nsDev, nsPid);
384     } catch(const std::exception& ex) {
385         try {
386             destroyNetdev(hostVeth);
387         } catch (const std::exception& ex) {
388             LOGE("Can't destroy netdev pipe: " << hostVeth << ", " << nsDev);
389         }
390         throw;
391     }
392 }
393
394 void createMacvlan(const pid_t& nsPid,
395                    const std::string& nsDev,
396                    const std::string& hostDev,
397                    const macvlan_mode& mode)
398 {
399     LOGT("Creating macvlan: host: " << hostDev << ", zone: " << nsDev << ", mode: " << mode);
400     createMacvlan(hostDev, nsDev, mode);
401     try {
402         up(nsDev);
403         moveToNS(nsDev, nsPid);
404     } catch(const std::exception& ex) {
405         try {
406             destroyNetdev(nsDev);
407         } catch (const std::exception& ex) {
408             LOGE("Can't destroy netdev: " << nsDev);
409         }
410         throw;
411     }
412 }
413
414 void movePhys(const pid_t& nsPid, const std::string& devId)
415 {
416     LOGT("Creating phys: dev: " << devId);
417     moveToNS(devId, nsPid);
418 }
419
420 std::vector<std::string> listNetdev(const pid_t& nsPid)
421 {
422     NetlinkMessage nlm(RTM_GETLINK, NLM_F_REQUEST|NLM_F_DUMP|NLM_F_ROOT);
423     ifinfomsg info = utils::make_clean<ifinfomsg>();
424     info.ifi_family = AF_PACKET;
425     nlm.put(info);
426     NetlinkResponse response = send(nlm, nsPid);
427     std::vector<std::string> interfaces;
428     while (response.hasMessage()) {
429         std::string ifName;
430         response.skip<ifinfomsg>();
431         // fetched value contains \0 terminator
432         int len = response.getAttributeLength();
433         response.fetch(IFLA_IFNAME, ifName, len - 1);
434         interfaces.push_back(ifName);
435         response.fetchNextMessage();
436     }
437     return interfaces;
438 }
439
440 void destroyNetdev(const std::string& netdev, const pid_t pid)
441 {
442     LOGT("Destroying netdev: " << netdev);
443     validateNetdevName(netdev);
444
445     NetlinkMessage nlm(RTM_DELLINK, NLM_F_REQUEST|NLM_F_ACK);
446     ifinfomsg infopeer = utils::make_clean<ifinfomsg>();
447     infopeer.ifi_family = AF_UNSPEC;
448     infopeer.ifi_change = 0xFFFFFFFF;
449     nlm.put(infopeer)
450         .put(IFLA_IFNAME, netdev);
451     send(nlm, pid);
452 }
453
454 void createBridge(const std::string& netdev)
455 {
456     LOGT("Creating bridge: " << netdev);
457     validateNetdevName(netdev);
458
459     NetlinkMessage nlm(RTM_NEWLINK, NLM_F_REQUEST | NLM_F_CREATE | NLM_F_EXCL | NLM_F_ACK);
460     ifinfomsg infoPeer = utils::make_clean<ifinfomsg>();
461     infoPeer.ifi_family = AF_UNSPEC;
462     infoPeer.ifi_change = 0xFFFFFFFF;
463     nlm.put(infoPeer)
464         .beginNested(IFLA_LINKINFO)
465             .put(IFLA_INFO_KIND, "bridge")
466             .beginNested(IFLA_INFO_DATA)
467                 .beginNested(IFLA_AF_SPEC)
468                     .put<uint32_t>(IFLA_BRIDGE_FLAGS, BRIDGE_FLAGS_MASTER)
469                 .endNested()
470             .endNested()
471         .endNested()
472         .put(IFLA_IFNAME, netdev);
473     send(nlm);
474 }
475
476 Attrs getAttrs(const pid_t nsPid, const std::string& netdev)
477 {
478     auto joinAddresses = [](const Attrs& attrs) -> std::string {
479         bool first = true;
480         std::stringstream ss;
481         for (const auto& attr : attrs) {
482             ss << (first ? "" : ",") << get<0>(attr) << ":" << get<1>(attr);
483             first = false;
484         }
485         return ss.str();
486     };
487
488     LOGT("Getting network device informations: " << netdev);
489     validateNetdevName(netdev);
490
491     NetlinkMessage nlm(RTM_GETLINK, NLM_F_REQUEST | NLM_F_ACK);
492     ifinfomsg infoPeer = utils::make_clean<ifinfomsg>();
493     infoPeer.ifi_family = AF_UNSPEC;
494     infoPeer.ifi_change = 0xFFFFFFFF;
495     nlm.put(infoPeer)
496         .put(IFLA_IFNAME, netdev);
497     Attrs attrs;
498     try {
499         NetlinkResponse response = send(nlm, nsPid);
500         if (!response.hasMessage()) {
501             throw VasumException("Can't get interface information");
502         }
503         response.fetch(infoPeer);
504
505         while (response.hasAttribute()) {
506             uint32_t mtu, link;
507             int attrType = response.getAttributeType();
508             switch (attrType) {
509                 case IFLA_MTU:
510                     response.fetch(IFLA_MTU, mtu);
511                     attrs.push_back(make_tuple("mtu", std::to_string(mtu)));
512                     break;
513                 case IFLA_LINK:
514                     response.fetch(IFLA_LINK, link);
515                     attrs.push_back(make_tuple("link", std::to_string(link)));
516                     break;
517                 default:
518                     response.skipAttribute();
519                     break;
520             }
521         }
522     } catch (const std::exception& ex) {
523         LOGE(ex.what());
524         throw VasumException(netdev + ": " + ex.what());
525     }
526
527     attrs.push_back(make_tuple("flags", std::to_string(infoPeer.ifi_flags)));
528     attrs.push_back(make_tuple("type", std::to_string(infoPeer.ifi_type)));
529     for (const auto& address : getIpAddresses(nsPid, AF_INET, infoPeer.ifi_index)) {
530         attrs.push_back(make_tuple("ipv4", joinAddresses(address)));
531     }
532
533     for (const auto& address : getIpAddresses(nsPid, AF_INET6, infoPeer.ifi_index)) {
534         attrs.push_back(make_tuple("ipv6", joinAddresses(address)));
535     }
536
537     return attrs;
538 }
539
540 void setAttrs(const pid_t nsPid, const std::string& netdev, const Attrs& attrs)
541 {
542     const std::set<std::string> supportedAttrs{"flags", "change", "type", "mtu", "link", "ipv4", "ipv6"};
543
544     LOGT("Setting network device informations: " << netdev);
545     validateNetdevName(netdev);
546     for (const auto& attr : attrs) {
547         if (supportedAttrs.find(get<0>(attr)) == supportedAttrs.end()) {
548             throw VasumException("Unsupported attribute: " + get<0>(attr));
549         }
550     }
551
552     NetlinkMessage nlm(RTM_NEWLINK, NLM_F_REQUEST | NLM_F_CREATE | NLM_F_ACK);
553     ifinfomsg infoPeer = utils::make_clean<ifinfomsg>();
554     infoPeer.ifi_family = AF_UNSPEC;
555     infoPeer.ifi_index = getInterfaceIndex(netdev, nsPid);
556     infoPeer.ifi_change = 0xFFFFFFFF;
557     for (const auto& attr : attrs) {
558         if (get<0>(attr) == "flags") {
559             infoPeer.ifi_flags = stoul(get<1>(attr));
560         }
561         if (get<0>(attr) == "change") {
562             infoPeer.ifi_change = stoul(get<1>(attr));
563         }
564         if (get<0>(attr) == "type") {
565             infoPeer.ifi_type = stoul(get<1>(attr));
566         }
567     }
568     nlm.put(infoPeer);
569     for (const auto& attr : attrs) {
570         if (get<0>(attr) == "mtu") {
571             nlm.put<uint32_t>(IFLA_MTU, stoul(get<1>(attr)));
572         }
573         if (get<0>(attr) == "link") {
574             nlm.put<uint32_t>(IFLA_LINK, stoul(get<1>(attr)));
575         }
576     }
577
578     NetlinkResponse response = send(nlm, nsPid);
579     if (!response.hasMessage()) {
580         throw VasumException("Can't set interface information");
581     }
582
583     //TODO: Multiple addresses should be set at once (add support NLM_F_MULTI to NetlinkMessage).
584     std::vector<std::string> ipv4;
585     std::vector<std::string> ipv6;
586     for (const auto& attr : attrs) {
587         if (get<0>(attr) == "ipv4") {
588             ipv4.push_back(get<1>(attr));
589         }
590         if (get<0>(attr) == "ipv6") {
591             ipv6.push_back(get<1>(attr));
592         }
593     }
594
595     auto setIp = [nsPid](const std::vector<std::string>& ips, uint32_t index, int family) -> void {
596         using namespace boost::algorithm;
597         for (const auto& ip : ips) {
598             Attrs attrs;
599             std::vector<std::string> params;
600             for (const auto& addrAttr : split(params, ip, is_any_of(","))) {
601                 size_t pos = addrAttr.find(":");
602                 if (pos == std::string::npos || pos == addrAttr.length()) {
603                     const std::string msg = "Wrong input data format: ill formed address attribute: " + addrAttr;
604                     LOGE(msg);
605                     throw VasumException(msg);
606                 }
607                 attrs.push_back(make_tuple(addrAttr.substr(0, pos), addrAttr.substr(pos + 1)));
608             }
609             setIpAddresses(nsPid, index, attrs, family);
610         }
611     };
612
613     setIp(ipv4, infoPeer.ifi_index, AF_INET);
614     setIp(ipv6, infoPeer.ifi_index, AF_INET6);
615 }
616
617 void deleteIpAddress(const pid_t nsPid,
618                      const std::string& netdev,
619                      const std::string& ip)
620 {
621     uint32_t index = getInterfaceIndex(netdev, nsPid);
622     size_t slash = ip.find('/');
623     if (slash == std::string::npos) {
624         const std::string msg = "Wrong address format: it is not CIDR notation: can't find '/'";
625         LOGE(msg);
626         throw VasumException(msg);
627     }
628     int prefixlen = 0;
629     try {
630         prefixlen = stoi(ip.substr(slash + 1));
631     } catch (const std::exception& ex) {
632         const std::string msg = "Wrong address format: invalid prefixlen";
633         LOGE(msg);
634         throw VasumException(msg);
635     }
636     deleteIpAddress(nsPid, index, ip.substr(0, slash), prefixlen, getIpFamily(ip));
637 }
638
639
640 } //namespace netdev
641 } //namespace vasum